diff --git a/Ide/src/IdeDoc.cpp b/Ide/src/IdeDoc.cpp --- a/Ide/src/IdeDoc.cpp +++ b/Ide/src/IdeDoc.cpp @@ -1,2130 +1,2132 @@ #include #include #include "lgi/common/Lgi.h" #include "lgi/common/Token.h" #include "lgi/common/Net.h" #include "lgi/common/ClipBoard.h" #include "lgi/common/DisplayString.h" #include "lgi/common/ScrollBar.h" #include "lgi/common/LgiRes.h" #include "lgi/common/Edit.h" #include "lgi/common/List.h" #include "lgi/common/PopupList.h" #include "lgi/common/TableLayout.h" #include "lgi/common/EventTargetThread.h" #include "lgi/common/CheckBox.h" #include "lgi/common/Http.h" #include "lgi/common/Menu.h" #include "lgi/common/FileSelect.h" #include "lgi/common/PopupNotification.h" #include "LgiIde.h" #include "ProjectNode.h" #include "SpaceTabConv.h" #include "DocEdit.h" #include "IdeDocPrivate.h" const char *Untitled = "[untitled]"; // static const char *White = " \r\t\n"; #define USE_OLD_FIND_DEFN 1 #define POPUP_WIDTH 700 // px #define POPUP_HEIGHT 350 // px enum { IDM_COPY_FILE = 1100, IDM_COPY_PATH, IDM_BROWSE }; int FileNameSorter(char **a, char **b) { char *A = strrchr(*a, DIR_CHAR); char *B = strrchr(*b, DIR_CHAR); return stricmp(A?A:*a, B?B:*b); } EditTray::EditTray(LTextView3 *ctrl, IdeDoc *doc) { Ctrl = ctrl; Doc = doc; Line = Col = 0; FuncBtn.ZOff(-1, -1); SymBtn.ZOff(-1, -1); int Ht = LSysFont->GetHeight() + 6; AddView(FileSearch = new LEdit(IDC_FILE_SEARCH, 0, 0, EDIT_CTRL_WIDTH, Ht)); AddView(FuncSearch = new LEdit(IDC_METHOD_SEARCH, 0, 0, EDIT_CTRL_WIDTH, Ht)); AddView(SymSearch = new LEdit(IDC_SYMBOL_SEARCH, 0, 0, EDIT_CTRL_WIDTH, Ht)); } EditTray::~EditTray() { } void EditTray::GotoSearch(int CtrlId, char *InitialText) { if (FileSearch && FileSearch->GetId() == CtrlId) { FileSearch->Name(InitialText); FileSearch->Focus(true); if (InitialText) FileSearch->SendNotify(LNotifyDocChanged); } if (FuncSearch && FuncSearch->GetId() == CtrlId) { FuncSearch->Name(InitialText); FuncSearch->Focus(true); if (InitialText) FuncSearch->SendNotify(LNotifyDocChanged); } if (SymSearch && SymSearch->GetId() == CtrlId) { SymSearch->Name(InitialText); SymSearch->Focus(true); if (InitialText) SymSearch->SendNotify(LNotifyDocChanged); } } void EditTray::OnCreate() { AttachChildren(); } int MeasureText(const char *s) { LDisplayString Ds(LSysFont, s); return Ds.X(); } #define HEADER_BTN_LABEL "h" #define FUNCTION_BTN_LABEL "{ }" #define SYMBOL_BTN_LABEL "s" void EditTray::OnPosChange() { LLayoutRect c(this, 2); c.Left(FileBtn, MeasureText(HEADER_BTN_LABEL)+10); if (FileSearch) c.Left(FileSearch, EDIT_CTRL_WIDTH); c.x1 += 8; c.Left(FuncBtn, MeasureText(FUNCTION_BTN_LABEL)+10); if (FuncSearch) c.Left(FuncSearch, EDIT_CTRL_WIDTH); c.x1 += 8; c.Left(SymBtn, MeasureText(SYMBOL_BTN_LABEL)+10); if (SymSearch) c.Left(SymSearch, EDIT_CTRL_WIDTH); c.x1 += 8; c.Remaining(TextMsg); } void EditTray::OnPaint(LSurface *pDC) { LRect c = GetClient(); pDC->Colour(L_MED); pDC->Rectangle(); LSysFont->Colour(L_TEXT, L_MED); LSysFont->Transparent(true); LString s; s.Printf("Cursor: %i,%i", Col, Line + 1); { LDisplayString ds(LSysFont, s); ds.Draw(pDC, TextMsg.x1, TextMsg.y1 + ((c.Y()-TextMsg.Y())/2), &TextMsg); } LRect f = FileBtn; LThinBorder(pDC, f, DefaultRaisedEdge); { LDisplayString ds(LSysFont, HEADER_BTN_LABEL); ds.Draw(pDC, f.x1 + 4, f.y1); } f = FuncBtn; LThinBorder(pDC, f, DefaultRaisedEdge); { LDisplayString ds(LSysFont, FUNCTION_BTN_LABEL); ds.Draw(pDC, f.x1 + 4, f.y1); } f = SymBtn; LThinBorder(pDC, f, DefaultRaisedEdge); { LDisplayString ds(LSysFont, SYMBOL_BTN_LABEL); ds.Draw(pDC, f.x1 + 4, f.y1); } } bool EditTray::Pour(LRegion &r) { LRect *c = FindLargest(r); if (c) { LRect n = *c; SetPos(n); return true; } return false; } void EditTray::OnHeaderList(LMouse &m) { // Header list button LArray Paths; if (Doc->BuildIncludePaths(Paths, PlatformCurrent, false)) { LArray Headers; if (Doc->BuildHeaderList(Ctrl->NameW(), Headers, Paths)) { // Sort them.. Headers.Sort(FileNameSorter); LSubMenu *s = new LSubMenu; if (s) { // Construct the menu LHashTbl, int> Map; int DisplayLines = GdcD->Y() / LSysFont->GetHeight(); if (Headers.Length() > (0.9 * DisplayLines)) { LArray Letters[26]; LArray Other; for (int i=0; i 1) { char *First = LGetLeaf(Letters[i][0]); char *Last = LGetLeaf(Letters[i].Last()); char Title[256]; sprintf_s(Title, sizeof(Title), "%s - %s", First, Last); LSubMenu *sub = s->AppendSub(Title); if (sub) { for (int n=0; n 0); sub->AppendItem(LGetLeaf(h), Id, true); } } } else if (Letters[i].Length() == 1) { char *h = Letters[i][0]; int Id = Map.Find(h); LAssert(Id > 0); s->AppendItem(LGetLeaf(h), Id, true); } } if (Other.Length() > 0) { for (int n=0; n 0); s->AppendItem(LGetLeaf(h), Id, true); } } } else { for (int i=0; i 0) s->AppendItem(LGetLeaf(h), Id, true); else LgiTrace("%s:%i - Failed to get id for '%s' (map.len=%i)\n", _FL, h, Map.Length()); } if (!Headers.Length()) { s->AppendItem("(none)", 0, false); } } // Show the menu LPoint p(m.x, m.y); PointToScreen(p); int Goto = s->Float(this, p.x, p.y, true); if (Goto > 0) { char *File = Headers[Goto-1]; if (File) { // Open the selected file Doc->GetProject()->GetApp()->OpenFile(File); } } DeleteObj(s); } } // Clean up memory Headers.DeleteArrays(); } else { LgiTrace("%s:%i - No include paths set.\n", _FL); } } void EditTray::OnFunctionList(LMouse &m) { LArray Funcs; if (BuildDefnList(Doc->GetFileName(), (char16*)Ctrl->NameW(), Funcs, DefnNone /*DefnFunc | DefnClass*/)) { LSubMenu s; LArray a; int ScreenHt = GdcD->Y(); int ScreenLines = ScreenHt / LSysFont->GetHeight(); float Ratio = ScreenHt ? (float)(LSysFont->GetHeight() * Funcs.Length()) / ScreenHt : 0.0f; bool UseSubMenus = Ratio > 0.9f; int Buckets = UseSubMenus ? (int)(ScreenLines * 0.9) : 1; int BucketSize = MAX(2, (int)Funcs.Length() / Buckets); LSubMenu *Cur = NULL; for (unsigned n=0; nType != DefnEnumValue) { for (char *k = i->Name; *k && o < Buf+sizeof(Buf)-8; k++) { if (*k == '&') { *o++ = '&'; *o++ = '&'; } else if (*k == '\t') { *o++ = ' '; } else { *o++ = *k; } } *o++ = 0; a[n] = i; if (UseSubMenus) { if (!Cur || n % BucketSize == 0) { LString SubMsg; SubMsg.Printf("%s...", Buf); Cur = s.AppendSub(SubMsg); } if (Cur) Cur->AppendItem(Buf, n+1, true); } else { s.AppendItem(Buf, n+1, true); } } } LPoint p(m.x, m.y); PointToScreen(p); int Goto = s.Float(this, p.x, p.y, true); if (Goto) { DefnInfo *Info = a[Goto-1]; if (Info) { Ctrl->SetLine(Info->Line); } } } else { LgiTrace("%s:%i - No functions in input.\n", _FL); } } void EditTray::OnSymbolList(LMouse &m) { LAutoString s(Ctrl->GetSelection()); if (s) { LAutoWString sw(Utf8ToWide(s)); if (sw) { #if USE_OLD_FIND_DEFN List Matches; Doc->FindDefn(sw, Ctrl->NameW(), Matches); #else LArray Matches; Doc->GetApp()->FindSymbol(s, Matches); #endif LSubMenu *s = new LSubMenu; if (s) { // Construct the menu int n=1; #if USE_OLD_FIND_DEFN for (auto Def: Matches) { char m[512]; char *d = strrchr(Def->File, DIR_CHAR); sprintf(m, "%s (%s:%i)", Def->Name.Get(), d ? d + 1 : Def->File.Get(), Def->Line); s->AppendItem(m, n++, true); } #else for (int i=0; iAppendItem(m, n++, true); } #endif if (!Matches.Length()) { s->AppendItem("(none)", 0, false); } // Show the menu LPoint p(m.x, m.y); PointToScreen(p); int Goto = s->Float(this, p.x, p.y, true); if (Goto) { #if USE_OLD_FIND_DEFN DefnInfo *Def = Matches[Goto-1]; #else FindSymResult *Def = &Matches[Goto-1]; #endif { // Open the selected symbol if (Doc->GetProject() && Doc->GetProject()->GetApp()) { AppWnd *App = Doc->GetProject()->GetApp(); IdeDoc *Doc = App->OpenFile(Def->File); if (Doc) { Doc->SetLine(Def->Line, false); } else { char *f = Def->File; LgiTrace("%s:%i - Couldn't open doc '%s'\n", _FL, f); } } else { LgiTrace("%s:%i - No project / app ptr.\n", _FL); } } } DeleteObj(s); } } } else { LSubMenu *s = new LSubMenu; if (s) { s->AppendItem("(No symbol currently selected)", 0, false); LPoint p(m.x, m.y); PointToScreen(p); s->Float(this, p.x, p.y, true); DeleteObj(s); } } } void EditTray::OnMouseClick(LMouse &m) { if (m.Left() && m.Down()) { if (FileBtn.Overlap(m.x, m.y)) { OnHeaderList(m); } else if (FuncBtn.Overlap(m.x, m.y)) { OnFunctionList(m); } else if (SymBtn.Overlap(m.x, m.y)) { OnSymbolList(m); } } } class ProjMethodPopup : public LPopupList { AppWnd *App; public: LArray All; ProjMethodPopup(AppWnd *app, LViewI *target) : LPopupList(target, PopupAbove, POPUP_WIDTH) { App = app; } LString ToString(DefnInfo *Obj) { return Obj->Name; } void OnSelect(DefnInfo *Obj) { App->GotoReference(Obj->File, Obj->Line, false); } bool Name(const char *s) { LString InputStr = s; LString::Array p = InputStr.SplitDelimit(" \t"); LArray Matching; for (unsigned i=0; iName, p[n])) { Match = false; break; } } if (Match) Matching.Add(Def); } return SetItems(Matching); } int OnNotify(LViewI *Ctrl, LNotification n) { if (Lst && Ctrl == Edit && (n.Type == LNotifyValueChanged || n.Type == LNotifyDocChanged)) { Name(Edit->Name()); } return LPopupList::OnNotify(Ctrl, n); } }; class ProjSymPopup : public LPopupList { AppWnd *App; IdeDoc *Doc; int CommonPathLen; public: LArray All; ProjSymPopup(AppWnd *app, IdeDoc *doc, LViewI *target) : LPopupList(target, PopupAbove, POPUP_WIDTH) { App = app; Doc = doc; CommonPathLen = 0; } void FindCommonPathLength() { LString s; for (unsigned i=0; iFile.Get(); char *b_end = strrchr(b, DIR_CHAR); int Common = 0; while ( *a && a <= a_end && *b && b <= b_end && ToLower(*a) == ToLower(*b)) { Common++; a++; b++; } if (i == 1) CommonPathLen = Common; else CommonPathLen = MIN(CommonPathLen, Common); } else s = All[i]->File; } } LString ToString(FindSymResult *Obj) { LString s; s.Printf("%s:%i - %s", CommonPathLen < Obj->File.Length() ? Obj->File.Get() + CommonPathLen : Obj->File.Get(), Obj->Line, Obj->Symbol.Get()); return s; } void OnSelect(FindSymResult *Obj) { App->GotoReference(Obj->File, Obj->Line, false); } int OnNotify(LViewI *Ctrl, LNotification n) { if (Lst && Ctrl == Edit && (n.Type == LNotifyValueChanged || n.Type == LNotifyDocChanged)) { // Kick off search... LString s = Ctrl->Name(); s = s.Strip(); if (s.Length() > 2) App->FindSymbol(Doc->AddDispatch(), s); } return LPopupList::OnNotify(Ctrl, n); } }; void FilterFiles(LArray &Perfect, LArray &Nodes, LString InputStr, int Platforms) { LString::Array p = InputStr.SplitDelimit(" \t"); auto InputLen = InputStr.RFind("."); if (InputLen < 0) InputLen = InputStr.Length(); LArray Partial; auto Start = LCurrentTime(); for (unsigned i=0; i 400) { break; } ProjectNode *Pn = Nodes[i]; if (! (Pn->GetPlatforms() & Platforms) ) continue; auto Fn = Pn->GetFileName(); if (Fn) { char *Dir = strchr(Fn, '/'); if (!Dir) Dir = strchr(Fn, '\\'); auto Leaf = Dir ? strrchr(Fn, *Dir) : Fn; bool Match = true; for (unsigned n=0; n { AppWnd *App; public: LArray Nodes; ProjFilePopup(AppWnd *app, LViewI *target) : LPopupList(target, PopupAbove, POPUP_WIDTH) { App = app; } LString ToString(ProjectNode *Obj) { return LString(Obj->GetFileName()); } void OnSelect(ProjectNode *Obj) { auto Fn = Obj->GetFileName(); if (LIsRelativePath(Fn)) { IdeProject *Proj = Obj->GetProject(); LAutoString Base = Proj->GetBasePath(); LFile::Path p(Base); p += Fn; App->GotoReference(p, 1, false); } else { App->GotoReference(Fn, 1, false); } } void Update(LString InputStr) { LArray Matches; FilterFiles(Matches, Nodes, InputStr, App->GetPlatform()); SetItems(Matches); } int OnNotify(LViewI *Ctrl, LNotification n) { if (Lst && Ctrl == Edit && (n.Type == LNotifyValueChanged || n.Type == LNotifyDocChanged)) { auto s = Ctrl->Name(); if (ValidStr(s)) Update(s); } return LPopupList::OnNotify(Ctrl, n); } }; class LStyleThread : public LEventTargetThread { public: LStyleThread() : LEventTargetThread("StyleThread") { } LMessage::Result OnEvent(LMessage *Msg) { switch (Msg->Msg()) { } return 0; } } StyleThread; //////////////////////////////////////////////////////////////////////////////////////////// IdeDocPrivate::IdeDocPrivate(IdeDoc *d, AppWnd *a, NodeSource *src, const char *file) : NodeView(src), LMutex("IdeDocPrivate.Lock") { FilePopup = NULL; MethodPopup = NULL; SymPopup = NULL; App = a; Doc = d; Project = 0; FileName = file; LFontType Font, *Use = 0; if (Font.Serialize(App->GetOptions(), OPT_EditorFont, false)) { Use = &Font; } Doc->AddView(Edit = new DocEdit(Doc, Use)); Doc->AddView(Tray = new EditTray(Edit, Doc)); } void IdeDocPrivate::OnDelete() { IdeDoc *Temp = Doc; DeleteObj(Temp); } void IdeDocPrivate::UpdateName() { char n[MAX_PATH_LEN+30]; LString Dsp = GetDisplayName(); char *File = Dsp; #if MDI_TAB_STYLE char *Dir = File ? strrchr(File, DIR_CHAR) : NULL; if (Dir) File = Dir + 1; #endif strcpy_s(n, sizeof(n), File ? File : Untitled); if (Edit->IsDirty()) { strcat(n, " (changed)"); } Doc->Name(n); } LString IdeDocPrivate::GetDisplayName() { if (nSrc) { auto Fn = nSrc->GetFileName(); if (Fn) { if (stristr(Fn, "://")) { LUri u(nSrc->GetFileName()); if (u.sPass) { u.sPass = "******"; } return u.ToString(); } else if (*Fn == '.') { return nSrc->GetFullPath(); } } return LString(Fn); } return LString(FileName); } bool IdeDocPrivate::IsFile(const char *File) { LString Mem; char *f = NULL; if (nSrc) { Mem = nSrc->GetFullPath(); f = Mem; } else { f = FileName; } if (!f) return false; LToken doc(f, DIR_STR); LToken in(File, DIR_STR); ssize_t in_pos = (ssize_t)in.Length() - 1; ssize_t doc_pos = (ssize_t)doc.Length() - 1; while (in_pos >= 0 && doc_pos >= 0) { char *i = in[in_pos--]; char *d = doc[doc_pos--]; if (!i || !d) { return false; } if (!strcmp(i, ".") || !strcmp(i, "..")) { continue; } if (stricmp(i, d)) { return false; } } return true; } const char *IdeDocPrivate::GetLocalFile() { if (nSrc) { if (nSrc->IsWeb()) return nSrc->GetLocalCache(); auto fp = nSrc->GetFullPath(); if (_stricmp(fp.Get()?fp.Get():"", Buffer.Get()?Buffer.Get():"")) Buffer = fp; return Buffer; } return FileName; } void IdeDocPrivate::SetFileName(const char *f) { nSrc = NULL; FileName = f; Edit->IsDirty(true); } bool IdeDocPrivate::Load() { bool Status = false; if (nSrc) { Status = nSrc->Load(Edit, this); } else if (FileName) { if (LFileExists(FileName)) { Status = Edit->Open(FileName); } else LgiTrace("%s:%i - '%s' doesn't exist.\n", _FL, FileName.Get()); } if (Status) ModTs = GetModTime(); return Status; } bool IdeDocPrivate::Save() { bool Status = false; if (nSrc) { Status = nSrc->Save(Edit, this); } else if (FileName) { Status = Edit->Save(FileName); if (!Status) { const char *Err = Edit->GetLastError(); LgiMsg(App, "%s", AppName, MB_OK, Err ? Err : "$unknown_error"); } OnSaveComplete(Status); } else { Edit->IsDirty(false); } if (Status) ModTs = GetModTime(); LPopupNotification::Message(Doc->GetWindow(), "Saved"); return Status; } void IdeDocPrivate::OnSaveComplete(bool Status) { if (Status) Edit->IsDirty(false); UpdateName(); ProjectNode *Node = dynamic_cast(nSrc); if (Node) { auto Full = nSrc->GetFullPath(); App->OnNode(Full, Node, FindSymbolSystem::FileReparse); } } void IdeDocPrivate::CheckModTime() { if (!ModTs.IsValid()) return; LDateTime Ts = GetModTime(); if (Ts.IsValid() && Ts > ModTs) { static bool InCheckModTime = false; if (!InCheckModTime) { InCheckModTime = true; if (!Edit->IsDirty() || LgiMsg(Doc, "Do you want to reload modified file from\ndisk and lose your changes?", AppName, MB_YESNO) == IDYES) { auto Ln = Edit->GetLine(); Load(); Edit->IsDirty(false); UpdateName(); Edit->SetLine((int)Ln); } InCheckModTime = false; } } } /////////////////////////////////////////////////////////////////////////////////////////// LString IdeDoc::CurIpDoc; int IdeDoc::CurIpLine = -1; IdeDoc::IdeDoc(AppWnd *a, NodeSource *src, const char *file) { d = new IdeDocPrivate(this, a, src, file); d->UpdateName(); /* if (src || file) d->Load(); */ } IdeDoc::~IdeDoc() { d->App->OnDocDestroy(this); DeleteObj(d); } class WebBuild : public LThread { IdeDocPrivate *d; LString Uri; int64 SleepMs; LStream *Log; LCancel Cancel; public: WebBuild(IdeDocPrivate *priv, LString uri, int64 sleepMs) : LThread("WebBuild"), d(priv), Uri(uri), SleepMs(sleepMs) { Log = d->App->GetBuildLog(); Run(); } ~WebBuild() { Cancel.Cancel(); while (!IsExited()) { LSleep(1); } } int Main() { if (SleepMs > 0) { // Sleep for a number of milliseconds to allow the file to upload/save to the website uint64 Ts = LCurrentTime(); while (!Cancel.IsCancelled() && (LCurrentTime()-Ts) < SleepMs) LSleep(1); } // Download the file... LStringPipe Out; LString Error; bool r = LgiGetUri(&Cancel, &Out, &Error, Uri, NULL/*InHdrs*/, NULL/*Proxy*/); if (r) { // Parse through it and extract any errors... } else { // Show the download error in the build log... Log->Print("%s:%i - Web build download failed: %s\n", _FL, Error.Get()); } return 0; } }; bool IdeDoc::Build() { if (!d->Edit) return false; int64 SleepMs = -1; LString s = d->Edit->Name(), Uri; LString::Array Lines = s.Split("\n"); for (auto Ln : Lines) { s = Ln.Strip(); if (s.Find("//") == 0) { LString::Array p = s(2,-1).Strip().Split(":", 1); if (p.Length() == 2) { if (p[0].Equals("build-sleep")) { SleepMs = p[1].Strip().Int(); } else if (p[0].Equals("build-uri")) { Uri = p[1].Strip(); break; } } } } if (Uri) { if (d->Build && !d->Build->IsExited()) { // Already building... LStream *Log = d->App->GetBuildLog(); if (Log) Log->Print("%s:%i - Already building...\n"); return false; } return d->Build.Reset(new WebBuild(d, Uri, SleepMs)); } return false; } void IdeDoc::OnLineChange(int Line) { d->App->OnLocationChange(d->GetLocalFile(), Line); } void IdeDoc::OnMarginClick(int Line) { LString Dn = d->GetDisplayName(); d->App->ToggleBreakpoint(Dn, Line); } void IdeDoc::OnTitleClick(LMouse &m) { LMdiChild::OnTitleClick(m); if (m.IsContextMenu()) { char Full[MAX_PATH_LEN] = "", sFile[MAX_PATH_LEN] = "", sFull[MAX_PATH_LEN] = "", sBrowse[MAX_PATH_LEN] = ""; const char *Fn = GetFileName(), *Dir = NULL; IdeProject *p = GetProject(); if (Fn) { strcpy_s(Full, sizeof(Full), Fn); if (LIsRelativePath(Fn) && p) { LAutoString Base = p->GetBasePath(); if (Base) LMakePath(Full, sizeof(Full), Base, Fn); } Dir = strrchr(Full, DIR_CHAR); if (Dir) sprintf_s(sFile, sizeof(sFile), "Copy '%s'", Dir + 1); sprintf_s(sFull, sizeof(sFull), "Copy '%s'", Full); sprintf_s(sBrowse, sizeof(sBrowse), "Browse to '%s'", Dir ? Dir + 1 : Full); } LSubMenu s; s.AppendItem("Save", IDM_SAVE, d->Edit->IsDirty()); s.AppendItem("Close", IDM_CLOSE, true); if (Fn) { s.AppendSeparator(); if (Dir) s.AppendItem(sFile, IDM_COPY_FILE, true); s.AppendItem(sFull, IDM_COPY_PATH, true); s.AppendItem(sBrowse, IDM_BROWSE, true); s.AppendItem("Show In Project", IDM_SHOW_IN_PROJECT, true); } if (p) { s.AppendSeparator(); s.AppendItem("Properties", IDM_PROPERTIES, true); } m.ToScreen(); int Cmd = s.Float(this, m.x, m.y, m.Left()); switch (Cmd) { case IDM_SAVE: { SetClean(NULL); break; } case IDM_CLOSE: { if (OnRequestClose(false)) Quit(); break; } case IDM_COPY_FILE: { if (Dir) { LClipBoard c(this); c.Text(Dir + 1); } break; } case IDM_COPY_PATH: { LClipBoard c(this); c.Text(Full); break; } case IDM_BROWSE: { LBrowseToFile(Full); break; } case IDM_SHOW_IN_PROJECT: { d->App->ShowInProject(Fn); break; } case IDM_PROPERTIES: { p->ShowFileProperties(Full); break; } } } } AppWnd *IdeDoc::GetApp() { return d->App; } bool IdeDoc::IsFile(const char *File) { return File ? d->IsFile(File) : false; } bool IdeDoc::AddBreakPoint(ssize_t Line, bool Add) { if (Add) d->BreakPoints.Add(Line, true); else d->BreakPoints.Delete(Line); if (d->Edit) d->Edit->Invalidate(); return true; } void IdeDoc::GotoSearch(int CtrlId, char *InitialText) { LString File; if (CtrlId == IDC_SYMBOL_SEARCH) { // Check if the cursor is on a #include line... in which case we // should look up the header and go to that instead of looking for // a symbol in the code. if (d->Edit) { // Get current line LString Ln = (*d->Edit)[d->Edit->GetLine()]; if (Ln.Find("#include") >= 0) { LString::Array a = Ln.SplitDelimit(" \t", 1); if (a.Length() == 2) { File = a[1].Strip("\'\"<>"); InitialText = File; CtrlId = IDC_FILE_SEARCH; } } } } if (d->Tray) d->Tray->GotoSearch(CtrlId, InitialText); } #define IsVariableChar(ch) \ ( \ IsAlpha(ch) \ || \ IsDigit(ch) \ || \ strchr("-_~", ch) != NULL \ ) void IdeDoc::SearchSymbol() { if (!d->Edit || !d->Tray) { LAssert(0); return; } ssize_t Cur = d->Edit->GetCaret(); auto Txt = d->Edit->NameW(); if (Cur >= 0 && Txt != NULL) { ssize_t Start = Cur; while ( Start > 0 && IsVariableChar(Txt[Start-1])) Start--; + ssize_t End = Cur; while ( Txt[End] && IsVariableChar(Txt[End])) End++; + LString Word(Txt + Start, End - Start); GotoSearch(IDC_SYMBOL_SEARCH, Word); } } void IdeDoc::UpdateControl() { if (d->Edit) d->Edit->Invalidate(); } void IdeDoc::SearchFile() { GotoSearch(IDC_FILE_SEARCH, NULL); } bool IdeDoc::IsCurrentIp() { auto Fn = GetFileName(); bool DocMatch = CurIpDoc && Fn && !_stricmp(Fn, CurIpDoc); return DocMatch; } void IdeDoc::ClearCurrentIp() { CurIpDoc.Empty(); CurIpLine = -1; } void IdeDoc::SetCrLf(bool CrLf) { if (d->Edit) d->Edit->SetCrLf(CrLf); } bool IdeDoc::OpenFile(const char *File) { if (!d->Edit) return false; auto Cs = d->GetSrc() ? d->GetSrc()->GetCharset() : NULL; return d->Edit->Open(File, Cs); } void IdeDoc::SetEditorParams(int IndentSize, int TabSize, bool HardTabs, bool ShowWhiteSpace) { if (d->Edit) { d->Edit->SetIndentSize(IndentSize > 0 ? IndentSize : 4); d->Edit->SetTabSize(TabSize > 0 ? TabSize : 4); d->Edit->SetHardTabs(HardTabs); d->Edit->SetShowWhiteSpace(ShowWhiteSpace); d->Edit->Invalidate(); } } bool IdeDoc::HasFocus(int Set) { if (!d->Edit) return false; if (Set) d->Edit->Focus(Set); return d->Edit->Focus(); } void IdeDoc::SplitSelection(LString Sep) { if (!d->Edit) return; auto r = d->Edit->GetSelectionRange(); LString s = d->Edit->GetSelection(); if (!s) return; auto parts = s.SplitDelimit(Sep); auto joined = LString("\n").Join(parts); LAutoWString w(Utf8ToWide(joined)); d->Edit->DeleteSelection(); d->Edit->Insert(r.Start, w, StrlenW(w)); } void IdeDoc::JoinSelection(LString Sep) { if (!d->Edit) return; auto r = d->Edit->GetSelectionRange(); LString s = d->Edit->GetSelection(); if (!s) return; LAutoWString w(Utf8ToWide(s.Replace("\n", Sep))); d->Edit->DeleteSelection(); d->Edit->Insert(r.Start, w, StrlenW(w)); } void IdeDoc::EscapeSelection(bool ToEscaped) { if (!d->Edit) return; LString s = d->Edit->GetSelection(); if (!s) return; auto ReplaceSelection = [this](LString s) { auto r = d->Edit->GetSelectionRange(); LAutoWString w(Utf8ToWide(s)); d->Edit->DeleteSelection(); d->Edit->Insert(r.Start, w, StrlenW(w)); }; if (ToEscaped) { LMouse m; GetMouse(m); LString Delim = "\r\n\\"; if (m.Ctrl()) { auto Inp = new LInput(this, LString::Escape(Delim, -1, "\\"), "Delimiter chars:", "Escape"); Inp->DoModal([this, ReplaceSelection, s, Inp](auto d, auto code) { if (code) { auto Delim = LString::UnEscape(Inp->GetStr().Get(), -1); auto str = LString::Escape(s, -1, Delim); ReplaceSelection(str); } delete d; }); return; } s = LString::Escape(s, -1, Delim); } else { s = LString::UnEscape(s.Get(), -1); } ReplaceSelection(s); } void IdeDoc::ConvertWhiteSpace(bool ToTabs) { if (!d->Edit) return; LAutoString Sp( ToTabs ? SpacesToTabs(d->Edit->Name(), d->Edit->GetTabSize()) : TabsToSpaces(d->Edit->Name(), d->Edit->GetTabSize()) ); if (Sp) { d->Edit->Name(Sp); SetDirty(); } } ssize_t IdeDoc::GetLine() { return d->Edit ? d->Edit->GetLine() : -1; } void IdeDoc::SetLine(int Line, bool CurIp) { if (CurIp) { LString CurDoc = GetFileName(); if (ValidStr(CurIpDoc) ^ ValidStr(CurDoc) || (CurIpDoc && CurDoc && strcmp(CurDoc, CurIpDoc) != 0) || Line != CurIpLine) { bool Cur = IsCurrentIp(); if (d->Edit && Cur && CurIpLine >= 0) { // Invalidate the old IP location d->Edit->InvalidateLine(CurIpLine - 1); } CurIpLine = Line; CurIpDoc = CurDoc; // LgiTrace("%s:%i - CurIpLine=%i\n", _FL, CurIpLine); d->Edit->InvalidateLine(CurIpLine - 1); } } if (d->Edit) { d->Edit->SetLine(Line); } } IdeProject *IdeDoc::GetProject() { return d->Project; } void IdeDoc::SetProject(IdeProject *p) { d->Project = p; if (d->Project->GetApp() && d->BreakPoints.Length() == 0) d->Project->GetApp()->LoadBreakPoints(this); } const char *IdeDoc::GetFileName() { return d->GetLocalFile(); } void IdeDoc::SetFileName(const char *f, bool Write) { d->SetFileName(f); if (Write) d->Edit->Save(d->GetLocalFile()); } void IdeDoc::Focus(bool f) { d->Edit->Focus(f); } LMessage::Result IdeDoc::OnEvent(LMessage *Msg) { switch (Msg->Msg()) { case M_FIND_SYM_REQUEST: { LAutoPtr Resp((FindSymRequest*)Msg->A()); if (Resp && d->SymPopup) { LViewI *SymEd; if (GetViewById(IDC_SYMBOL_SEARCH, SymEd)) { LString Input = SymEd->Name(); if (Input == Resp->Str) // Is the input string still the same? { /* The problem with this is that the user it still typing something and the cursor / focus jumps to the document now they are typing a search string into the document, which is not what they intended. if (Resp->Results.Length() == 1) { FindSymResult *r = Resp->Results[0]; d->SymPopup->Visible(false); d->App->GotoReference(r->File, r->Line, false); } else */ { d->SymPopup->All = Resp->Results; Resp->Results.Length(0); d->SymPopup->FindCommonPathLength(); d->SymPopup->SetItems(d->SymPopup->All); d->SymPopup->Visible(true); } } } } break; } } return LMdiChild::OnEvent(Msg); } void IdeDoc::OnPulse() { d->CheckModTime(); if (d->Lock(_FL)) { if (d->WriteBuf.Length()) { bool Pour = d->Edit->SetPourEnabled(false); for (auto s: d->WriteBuf) { LAutoWString w(Utf8ToWide(s, s.Length())); d->Edit->Insert(d->Edit->Length(), w, Strlen(w.Get())); } d->Edit->SetPourEnabled(Pour); d->WriteBuf.Empty(); d->Edit->Invalidate(); } d->Unlock(); } } LString IdeDoc::Read() { return d->Edit->Name(); } ssize_t IdeDoc::Write(const void *Ptr, ssize_t Size, int Flags) { if (d->Lock(_FL)) { d->WriteBuf.New().Set((char*)Ptr, Size); d->Unlock(); } return 0; } void IdeDoc::OnProjectChange() { DeleteObj(d->FilePopup); DeleteObj(d->MethodPopup); DeleteObj(d->SymPopup); } int IdeDoc::OnNotify(LViewI *v, LNotification n) { // printf("IdeDoc::OnNotify(%i, %i)\n", v->GetId(), f); switch (v->GetId()) { case IDC_EDIT: { switch (n.Type) { case LNotifyDocChanged: { d->UpdateName(); break; } case LNotifyCursorChanged: { if (d->Tray) { LPoint Pt; if (d->Edit->GetLineColumnAtIndex(Pt, d->Edit->GetCaret())) { d->Tray->Col = Pt.x; d->Tray->Line = Pt.y; d->Tray->Invalidate(); } } break; } default: break; } break; } case IDC_FILE_SEARCH: { if (n.Type == LNotifyEscapeKey) { d->Edit->Focus(true); break; } auto SearchStr = v->Name(); if (ValidStr(SearchStr)) { if (!d->FilePopup) { if ((d->FilePopup = new ProjFilePopup(d->App, v))) { // Populate with files from the project... // Find the root project... IdeProject *p = d->Project; while (p && p->GetParentProject()) p = p->GetParentProject(); if (p) { // Get all the nodes List All; p->GetChildProjects(All); All.Insert(p); for (auto p: All) { p->GetAllNodes(d->FilePopup->Nodes); } } } } if (d->FilePopup) { // Update list elements... d->FilePopup->OnNotify(v, n); } } else if (d->FilePopup) { DeleteObj(d->FilePopup); } break; } case IDC_METHOD_SEARCH: { if (n.Type == LNotifyEscapeKey) { printf("%s:%i Got LNotifyEscapeKey\n", _FL); d->Edit->Focus(true); break; } auto SearchStr = v->Name(); if (ValidStr(SearchStr)) { if (!d->MethodPopup) d->MethodPopup = new ProjMethodPopup(d->App, v); if (d->MethodPopup) { // Populate with symbols d->MethodPopup->All.Length(0); BuildDefnList(GetFileName(), (char16*)d->Edit->NameW(), d->MethodPopup->All, DefnFunc); // Update list elements... d->MethodPopup->OnNotify(v, n); } } else if (d->MethodPopup) { DeleteObj(d->MethodPopup); } break; } case IDC_SYMBOL_SEARCH: { if (n.Type == LNotifyEscapeKey) { printf("%s:%i Got LNotifyEscapeKey\n", _FL); d->Edit->Focus(true); break; } auto SearchStr = v->Name(); if (ValidStr(SearchStr)) { if (!d->SymPopup) d->SymPopup = new ProjSymPopup(d->App, this, v); if (d->SymPopup) d->SymPopup->OnNotify(v, n); } else if (d->SymPopup) { DeleteObj(d->SymPopup); } break; } } return 0; } void IdeDoc::SetDirty() { d->Edit->IsDirty(true); d->UpdateName(); } bool IdeDoc::GetClean() { return !d->Edit->IsDirty(); } LString IdeDoc::GetFullPath() { LAutoString Base; if (GetProject()) Base = GetProject()->GetBasePath(); LString LocalPath; if (d->GetLocalFile() && LIsRelativePath(LocalPath) && Base) { char p[MAX_PATH_LEN]; LMakePath(p, sizeof(p), Base, d->GetLocalFile()); LocalPath = p; } else { LocalPath = d->GetLocalFile(); } if (d->Project) d->Project->CheckExists(LocalPath); return LocalPath; } void IdeDoc::SetClean(std::function Callback) { static bool Processing = false; if (!Processing) { Processing = true; LAutoString Base; if (GetProject()) Base = GetProject()->GetBasePath(); LString LocalPath = GetFullPath(); // printf("OnSave setup d=%p\n", d); auto OnSave = [this, Callback](bool ok) { // printf("OnSave %i d=%p\n", ok, d); if (ok) d->Save(); // printf("OnSave cb\n"); if (Callback) Callback(ok); // printf("OnSave done\n"); }; if (d->Edit->IsDirty() && !LFileExists(LocalPath)) { // We need a valid filename to save to... auto s = new LFileSelect; s->Parent(this); if (Base) s->InitialDir(Base); s->Save([this, OnSave](auto fileSel, auto ok) { // printf("Doc.Save.Cb ok=%i d=%p\n", ok, d); if (ok) d->SetFileName(fileSel->Name()); // printf("Doc.Save.Cb onsave\n", ok); OnSave(ok); // printf("Doc.Save.Cb del\n", ok); delete fileSel; }); } else OnSave(true); Processing = false; } } void IdeDoc::OnPaint(LSurface *pDC) { LMdiChild::OnPaint(pDC); #if !MDI_TAB_STYLE LRect c = GetClient(); LWideBorder(pDC, c, SUNKEN); #endif } void IdeDoc::OnPosChange() { LMdiChild::OnPosChange(); } bool IdeDoc::OnRequestClose(bool OsShuttingDown) { if (d->Edit->IsDirty()) { LString Dsp = d->GetDisplayName(); int a = LgiMsg(this, "Save '%s'?", AppName, MB_YESNOCANCEL, Dsp ? Dsp.Get() : Untitled); switch (a) { case IDYES: { SetClean([](bool ok) { if (ok) { LAssert(!"Impl close doc."); } }); // This is returned immediately... before the user has decided to save or not return false; } case IDNO: { break; } default: case IDCANCEL: { return false; } } } return true; } /* LTextView3 *IdeDoc::GetEdit() { return d->Edit; } */ bool IdeDoc::BuildIncludePaths(LArray &Paths, IdePlatform Platform, bool IncludeSysPaths) { if (!GetProject()) { LgiTrace("%s:%i - GetProject failed.\n", _FL); return false; } bool Status = GetProject()->BuildIncludePaths(Paths, true, IncludeSysPaths, Platform); if (Status) { if (IncludeSysPaths) GetApp()->GetSystemIncludePaths(Paths); } else { LgiTrace("%s:%i - GetProject()->BuildIncludePaths failed.\n", _FL); } return Status; } bool IdeDoc::BuildHeaderList(const char16 *Cpp, LArray &Headers, LArray &IncPaths) { LAutoString c8(WideToUtf8(Cpp)); if (!c8) return false; return ::BuildHeaderList(c8, Headers, IncPaths, true); } bool MatchSymbol(DefnInfo *Def, char16 *Symbol) { static char16 Dots[] = {':', ':', 0}; LBase o; o.Name(Def->Name); auto Name = o.NameW(); auto Sep = StristrW((char16*)Name, Dots); auto Start = Sep ? Sep : Name; // char16 *End = StrchrW(Start, '('); ssize_t Len = StrlenW(Symbol); char16 *Match = StristrW((char16*)Start, Symbol); if (Match) // && Match + Len <= End) { if (Match > Start && isword(Match[-1])) { return false; } char16 *e = Match + Len; if (*e && isword(*e)) { return false; } return true; } return false; } bool IdeDoc::FindDefn(char16 *Symbol, const char16 *Source, List &Matches) { if (!Symbol || !Source) { LgiTrace("%s:%i - Arg error.\n", _FL); return false; } #if DEBUG_FIND_DEFN LStringPipe Dbg; LgiTrace("FindDefn(%S)\n", Symbol); #endif LString::Array Paths; LArray Headers; if (!BuildIncludePaths(Paths, PlatformCurrent, true)) { LgiTrace("%s:%i - BuildIncludePaths failed.\n", _FL); // return false; } char Local[MAX_PATH_LEN]; strcpy_s(Local, sizeof(Local), GetFileName()); LTrimDir(Local); Paths.New() = Local; if (!BuildHeaderList(Source, Headers, Paths)) { LgiTrace("%s:%i - BuildHeaderList failed.\n", _FL); // return false; } { LArray Defns; for (int i=0; i Defns; if (BuildDefnList(h, c16, Defns, DefnNone, false )) { bool Found = false; for (unsigned n=0; n 0; } diff --git a/Ide/src/SimpleCppParser.cpp b/Ide/src/SimpleCppParser.cpp --- a/Ide/src/SimpleCppParser.cpp +++ b/Ide/src/SimpleCppParser.cpp @@ -1,982 +1,1001 @@ /* Known bugs: 1) Duplicate brackets in #defines, e.g: #if SOME_DEF if (expr) { #else if (different_expr) { #endif Breaks the bracket counting. Causing the depth to get out of sync with capture... Workaround: Move the brackets outside of the #define'd area if possible. 2) This syntax is wrongly assumed to be a structure: struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback) { ... } Can't find these symbols: do_recv (in api_msg.c) process_apcp_msg (in ape-apcp.c) recv_udp (in api_msg.c) Wrong position: lwip_select (out by 4 lines?) nad_apcp_send tcpip_callback_with_block appears 3 times? */ #include "lgi/common/Lgi.h" #include "lgi/common/DocView.h" #include "ParserCommon.h" -// #define DEBUG_FILE "Gdc2.h" +// #define DEBUG_FILE "IdeProject.cpp" // #define DEBUG_LINE 65 const char *TypeToStr(DefnType t) { switch (t) { default: case DefnNone: return "DefnNone"; case DefnDefine: return "DefnDefine"; case DefnFunc: return "DefnFunc"; case DefnClass: return "DefnClass"; case DefnEnum: return "DefnEnum"; case DefnEnumValue: return "DefnEnumValue"; case DefnTypedef: return "DefnTypedef"; case DefnVariable: return "DefnVariable"; } } bool IsFirst(LArray &a, int depth) { if (depth == 0) return true; for (int i=0; i 1) return false; return true; } bool IsFuncNameChar(char c) { return strchr("_:=~[]<>-+", c) || IsAlpha(c) || IsDigit(c); } bool ParseFunction(LRange &Return, LRange &Name, LRange &Args, const char *Defn) { if (!Defn) return false; int Depth = 0; const char *c, *Last = NULL; for (c = Defn; *c; c++) { if (*c == '(') { if (Depth == 0) Last = c; Depth++; } else if (*c == ')') { if (Depth > 0) Depth--; else { LgiTrace("%s:%i - Fn parse error '%s' (%i)\n", _FL, Defn, (int)(c - Defn)); return false; } } } if (!Last) return false; Args.Start = Last - Defn; Args.Len = c - Last; while (Last > Defn && IsWhiteSpace(Last[-1])) Last--; while (Last > Defn && IsFuncNameChar(Last[-1])) Last--; Return.Start = 0; Return.Len = Last - Defn; Name.Start = Last - Defn; Name.Len = Args.Start - Name.Start; if (Name.Len == 0 || Args.Len == 0) { /* LgiTrace("%s:%i - Fn parse empty section '%s' (%i,%i,%i)\n", _FL, Defn, (int)Return.Len, (int)Name.Len, (int)Args.Len); */ return false; } return true; } bool SeekPtr(char16 *&s, char16 *end, int &Line) { if (s > end) { LAssert(0); return false; } while (s < end) { if (*s == '\n') Line++; s++; } return true; } DefnType GuessDefnType(char16 *def, bool debug) { // In the context of a class member, this could be a variable defn: // // bool myVar = true; // bool myVar = someFn(); // // or a function defn: // // bool myFunction(int someArg = 10); // // Try to guess which it is: int roundDepth = 0; int equalsAtZero = 0; for (auto s = def; *s; s++) { if (*s == '(') roundDepth++; else if (*s == ')') roundDepth--; else if (*s == '=') { if (roundDepth == 0) equalsAtZero++; } } /* if (equalsAtZero && debug) printf("equalsAtZero: %S\n", def); */ return equalsAtZero ? DefnVariable : DefnFunc; } bool BuildCppDefnList(const char *FileName, char16 *Cpp, LArray &Defns, int LimitTo, bool Debug) { if (!Cpp) return false; static char16 StrClass[] = {'c', 'l', 'a', 's', 's', 0}; static char16 StrStruct[] = {'s', 't', 'r', 'u', 'c', 't', 0}; static char16 StrEnum[] = {'e', 'n', 'u', 'm', 0}; static char16 StrOpenBracket[] = {'{', 0}; static char16 StrColon[] = {':', 0}; static char16 StrSemiColon[] = {';', 0}; static char16 StrDefine[] = {'d', 'e', 'f', 'i', 'n', 'e', 0}; static char16 StrExtern[] = {'e', 'x', 't', 'e', 'r', 'n', 0}; static char16 StrTypedef[] = {'t', 'y', 'p', 'e', 'd', 'e', 'f', 0}; static char16 StrC[] = {'\"', 'C', '\"', 0}; static char16 StrHash[] = {'#', 0}; char WhiteSpace[] = " \t\r\n"; char16 *s = Cpp; char16 *LastDecl = s; int Depth = 0; int Line = 0; #ifdef DEBUG_LINE int PrevLine = 0; #endif int CaptureLevel = 0; int InClass = false; // true if we're in a class definition char16 *CurClassDecl = 0; bool IsEnum = 0, IsClass = false, IsStruct = false; bool FnEmit = false; // don't emit functions between a f(n) and the next '{' // they are only parent class initializers LArray ConditionalIndex; int ConditionalDepth = 0; bool ConditionalFirst = true; bool ConditionParsingErr = false; #ifdef DEBUG_FILE Debug |= FileName && stristr(FileName, DEBUG_FILE) != NULL; #endif while (s && *s) { // skip ws while (*s && strchr(" \t\r", *s)) s++; #ifdef DEBUG_LINE if (Debug) { if (Line >= DEBUG_LINE - 1) { // int asd=0; } else if (PrevLine != Line) { PrevLine = Line; // LgiTrace("%s:%i '%.10S'\n", FileName, Line + 1, s); } } #endif // tackle decl switch (*s) { case 0: break; case '\n': { Line ++; s++; break; } case '#': { const char16 *Hash = s; s++; skipws(s) const char16 *End = s; while (*End && IsAlpha(*End)) End++; if ( ( LimitTo == DefnNone || (LimitTo & DefnDefine) != 0 ) && (End - s) == 6 && StrncmpW(StrDefine, s, 6) == 0 ) { s += 6; defnskipws(s); LexCpp(s, LexNoReturn); char16 r = *s; *s = 0; Defns.New().Set(DefnDefine, FileName, Hash, Line + 1); *s = r; } char16 *Eol = Strchr(s, '\n'); if (!Eol) Eol = s + Strlen(s); // bool IsIf = false, IsElse = false, IsElseIf = false; if ( ((End - s) == 2 && !Strncmp(L"if", s, End - s)) || ((End - s) == 5 && !Strncmp(L"ifdef", s, End - s)) || ((End - s) == 6 && !Strncmp(L"ifndef", s, End - s)) ) { ConditionalIndex[ConditionalDepth] = 1; ConditionalDepth++; ConditionalFirst = IsFirst(ConditionalIndex, ConditionalDepth); if (Debug) LgiTrace("%s:%i - ConditionalDepth++=%i Line=%i: %.*S\n", _FL, ConditionalDepth, Line+1, Eol - s + 1, s - 1); } else if ( ((End - s) == 4 && !Strncmp(L"else", s, End - s)) || ((End - s) == 7 && !Strncmp(L"else if", s, 7)) ) { if (ConditionalDepth <= 0 && !ConditionParsingErr) { ConditionParsingErr = true; LgiTrace("%s:%i - Error parsing pre-processor conditions: %s:%i\n", _FL, FileName, Line+1); } if (ConditionalDepth > 0) { ConditionalIndex[ConditionalDepth-1]++; ConditionalFirst = IsFirst(ConditionalIndex, ConditionalDepth); if (Debug) LgiTrace("%s:%i - ConditionalDepth=%i Idx++ Line=%i: %.*S\n", _FL, ConditionalDepth, Line+1, Eol - s + 1, s - 1); } } else if ( ((End - s) == 5 && !Strncmp(L"endif", s, End - s)) ) { if (ConditionalDepth <= 0 && !ConditionParsingErr) { ConditionParsingErr = true; LgiTrace("%s:%i - Error parsing pre-processor conditions: %s:%i\n", _FL, FileName, Line+1); } if (ConditionalDepth > 0) ConditionalDepth--; ConditionalFirst = IsFirst(ConditionalIndex, ConditionalDepth); if (Debug) LgiTrace("%s:%i - ConditionalDepth--=%i Line=%i: %.*S\n", _FL, ConditionalDepth, Line+1, Eol - s + 1, s - 1); } while (*s) { if (*s == '\n') { // could be end of # command char Last = (s[-1] == '\r') ? s[-2] : s[-1]; if (Last != '\\') break; Line++; } s++; LastDecl = s; } break; } case '\"': case '\'': { char16 Delim = *s; s++; while (*s) { if (*s == Delim) { s++; break; } if (*s == '\\') s++; if (*s == '\n') Line++; s++; } break; } case '{': { s++; if (ConditionalFirst) Depth++; FnEmit = false; #ifdef DEBUG_FILE if (Debug) LgiTrace("%s:%i - FnEmit=%i Depth=%i @ line %i\n", _FL, FnEmit, Depth, Line+1); #endif break; } case '}': { s++; if (ConditionalFirst) { if (Depth > 0) { Depth--; #ifdef DEBUG_FILE if (Debug) LgiTrace("%s:%i - CaptureLevel=%i Depth=%i @ line %i\n", _FL, CaptureLevel, Depth, Line+1); #endif } else { #ifdef DEBUG_FILE if (Debug) LgiTrace("%s:%i - ERROR Depth already=%i @ line %i\n", _FL, Depth, Line+1); #endif } } defnskipws(s); LastDecl = s; if (IsEnum) { if (IsAlpha(*s)) // typedef'd enum? { LAutoWString t(LexCpp(s, LexStrdup)); if (t) Defns.New().Set(DefnEnum, FileName, t.Get(), Line + 1); } IsEnum = false; } break; } case ';': { s++; LastDecl = s; if (Depth == 0 && InClass) { // Check for typedef struct name char16 *Start = s - 1; while (Start > Cpp && Start[-1] != '}') Start--; LString TypeDef = LString(Start, s - Start - 1).Strip(); if (TypeDef.Length() > 0) { if (LimitTo == DefnNone || (LimitTo & DefnClass) != 0) { Defns.New().Set(DefnClass, FileName, TypeDef, Line + 1); } } // End the class def InClass = false; CaptureLevel = 0; #ifdef DEBUG_FILE if (Debug) LgiTrace("%s:%i - CaptureLevel=%i Depth=%i @ line %i\n", _FL, CaptureLevel, Depth, Line+1); #endif DeleteArray(CurClassDecl); } break; } case '/': { s++; if (*s == '/') { // one line comment while (*s && *s != '\n') s++; LastDecl = s; } else if (*s == '*') { // multi line comment s++; while (*s) { if (s[0] == '*' && s[1] == '/') { s += 2; break; } if (*s == '\n') Line++; s++; } LastDecl = s; } break; } case '(': { s++; if (Depth == CaptureLevel && !FnEmit && LastDecl && ConditionalFirst) { // function? // find start: char16 *Start = LastDecl; skipws(Start); if (Strnstr(Start, L"__attribute__", s - Start)) break; // find end (matching closing bracket) int RoundDepth = 1; char16 *End = s; while (*End) { if (*End == '/' && End[1] == '/') { End = Strchr(End, '\n'); if (!End) break; } if (*End == '(') { RoundDepth++; } else if (*End == ')') { if (--RoundDepth == 0) break; } End++; } if (End && *End) { End++; auto Buf = NewStrW(Start, End-Start); if (Buf) { // remove new-lines auto Out = Buf; for (auto In = Buf; *In; In++) { if (*In == '\r' || *In == '\n' || *In == '\t' || *In == ' ') { *Out++ = ' '; skipws(In); In--; } else if (In[0] == '/' && In[1] == '/') { In = StrchrW(In, '\n'); if (!In) break; } else { *Out++ = *In; } } *Out++ = 0; if (CurClassDecl) { char16 Str[1024]; ZeroObj(Str); StrncpyW(Str, Buf, CountOf(Str)); char16 *b = StrchrW(Str, '('); if (b) { // Skip whitespace between name and '(' while ( b > Str && strchr(WhiteSpace, b[-1]) ) { b--; } // Skip over to the start of the name.. while ( b > Str && b[-1] != '*' && b[-1] != '&' && !strchr(WhiteSpace, b[-1]) ) { b--; } auto ClsLen = StrlenW(CurClassDecl); auto BLen = StrlenW(b); if (ClsLen + BLen + 1 > CountOf(Str)) { LgiTrace("%s:%i - Defn too long: %i\n", _FL, ClsLen + BLen + 1); } else { memmove(b + ClsLen + 2, b, sizeof(*b) * (BLen+1)); memcpy(b, CurClassDecl, sizeof(*b) * ClsLen); b += ClsLen; *b++ = ':'; *b++ = ':'; DeleteArray(Buf); Buf = NewStrW(Str); } } } // cache f(n) def auto Type = GuessDefnType(Buf, Debug); if ( ( LimitTo == DefnNone || (LimitTo & Type) != 0 ) && *Buf != ')' ) Defns.New().Set(Type, FileName, Buf, Line + 1); DeleteArray(Buf); while (*End && !strchr(";:{#", *End)) End++; SeekPtr(s, End, Line); FnEmit = *End != ';'; #if 0 // def DEBUG_FILE if (Debug) LgiTrace("%s:%i - FnEmit=%i Depth=%i @ line %i\n", _FL, FnEmit, Depth, Line+1); #endif } } } else { #ifdef DEBUG_FILE if (Debug) LgiTrace("%s:%i - Not attempting fn parse: depth=%i, capture=%i, fnEmit=%i, CondFirst=%i, %s:%i:%.20S\n", _FL, Depth, CaptureLevel, FnEmit, ConditionalFirst, LGetLeaf(FileName), Line, s-1); #endif } break; } default: { bool InTypedef = false; if (IsAlpha(*s) || IsDigit(*s) || *s == '_') { char16 *Start = s; s++; defnskipsym(s); auto TokLen = s - Start; if (TokLen == 6 && StrncmpW(StrExtern, Start, 6) == 0) { // extern "C" block char16 *t = LexCpp(s, LexStrdup); // "C" if (t && StrcmpW(t, StrC) == 0) { defnskipws(s); if (*s == '{') { Depth--; } } DeleteArray(t); } else if (TokLen == 7 && StrncmpW(StrTypedef, Start, 7) == 0) { // Typedef skipws(s); IsStruct = !Strnicmp(StrStruct, s, StrlenW(StrStruct)); IsClass = !Strnicmp(StrClass, s, StrlenW(StrClass)); if (IsStruct || IsClass) { Start = s; InTypedef = true; goto DefineStructClass; } IsEnum = !Strnicmp(StrEnum, s, StrlenW(StrEnum)); if (IsEnum) { Start = s; s += 4; goto DefineEnum; } LStringPipe p; char16 *i; for (i = Start; i && *i;) { switch (*i) { case ' ': case '\t': { p.Push(Start, i - Start); defnskipws(i); char16 sp[] = {' ', 0}; p.Push(sp); Start = i; break; } case '\n': Line++; // fall thru case '\r': { p.Push(Start, i - Start); i++; Start = i; break; } case '{': { p.Push(Start, i - Start); int Depth = 1; i++; while (*i && Depth > 0) { switch (*i) { case '{': Depth++; break; case '}': Depth--; break; case '\n': Line++; break; } i++; } Start = i; break; } case ';': { p.Push(Start, i - Start); s = i; i = 0; break; } default: { i++; break; } } } char16 *Typedef = p.NewStrW(); if (Typedef) { if (LimitTo == DefnNone || (LimitTo & DefnTypedef) != 0) { Defns.New().Set(DefnTypedef, FileName, Typedef, Line + 1); } DeleteArray(Typedef); } } else if ( ( TokLen == 5 && (IsClass = !StrncmpW(StrClass, Start, 5)) ) || ( TokLen == 6 && (IsStruct = !StrncmpW(StrStruct, Start, 6)) ) ) { DefineStructClass: // Class / Struct if (Depth == 0) { // Check if this is really a class/struct definition or just a reference char16 *next = s; while (*next) { // If we seek to the next line, check it's not a preprocessor directive. if (*next == '\n') { next++; while (*next && strchr(WhiteSpace, *next)) next++; if (*next == '#') { // Skip the processor line... while (*next && *next != '\n') next++; } continue; } else if (strchr(";(){", *next)) break; next++; } if (*next == '{') { // Full definition InClass = true; CaptureLevel = 1; #ifdef DEBUG_FILE if (Debug) - LgiTrace("%s:%i - CaptureLevel=%i Depth=%i @ line %i\n", _FL, CaptureLevel, Depth, Line+1); + LgiTrace("%s:%i - CLASS/STRUCT defn: CaptureLevel=%i Depth=%i @ line %i\n", _FL, CaptureLevel, Depth, Line+1); #endif char16 *n = Start + (IsClass ? StrlenW(StrClass) : StrlenW(StrStruct)), *t; List Tok; while (n && *n) { char16 *Last = n; if ((t = LexCpp(n, LexStrdup))) { + #ifdef DEBUG_FILE + if (Debug) + LgiTrace(" t='%S' @ line %i\n", t, Line+1); + #endif + if (StrcmpW(t, StrSemiColon) == 0) { DeleteArray(t); break; } else if (StrcmpW(t, StrHash) || StrcmpW(t, StrOpenBracket) == 0 || StrcmpW(t, StrColon) == 0) { DeleteArray(CurClassDecl); - CurClassDecl = *Tok.rbegin(); - Tok.Delete(CurClassDecl); + if (Tok.Length() > 0) + { + CurClassDecl = *Tok.rbegin(); + Tok.Delete(CurClassDecl); + } + else + { + CurClassDecl = t; + t = NULL; + } if (LimitTo == DefnNone || (LimitTo & DefnClass) != 0) { char16 r = *Last; *Last = 0; Defns.New().Set(DefnClass, FileName, Start, Line + 1); *Last = r; SeekPtr(s, next, Line); } + + #ifdef DEBUG_FILE + if (Debug) + LgiTrace(" class='%S' @ line %i\n", CurClassDecl, Line+1); + #endif + DeleteArray(t); break; } else { Tok.Insert(t); } } else { LgiTrace("%s:%i - LexCpp failed at %s:%i.\n", _FL, FileName, Line+1); break; } } Tok.DeleteArrays(); } else if (InTypedef) { // Typedef'ing some other structure... // char16 *Start = s; LexCpp(s, LexNoReturn); defnskipws(s); LArray a; char16 *t; ssize_t StartRd = -1, EndRd = -1; while ((t = LexCpp(s, LexStrdup))) { if (StartRd < 0 && !StrcmpW(t, L"(")) StartRd = a.Length(); else if (EndRd < 0 && !StrcmpW(t, L")")) EndRd = a.Length(); if (!StrcmpW(t, StrSemiColon)) break; a.Add(t); } if (a.Length()) { auto iName = StartRd > 0 && EndRd > StartRd ? StartRd - 1 : a.Length() - 1; auto sName = a[iName]; Defns.New().Set(DefnTypedef, FileName, sName, Line + 1); a.DeleteArrays(); } } } } else if ( TokLen == 4 && StrncmpW(StrEnum, Start, 4) == 0 ) { DefineEnum: IsEnum = true; defnskipws(s); LAutoWString t(LexCpp(s, LexStrdup)); if (t && isalpha(*t)) { Defns.New().Set(DefnEnum, FileName, t.Get(), Line + 1); } } else if (IsEnum) { char16 r = *s; *s = 0; Defns.New().Set(DefnEnumValue, FileName, Start, Line + 1); *s = r; defnskipws(s); if (*s == '=') { s++; while (true) { defnskipws(s); defnskipsym(s); defnskipws(s); if (*s == 0 || *s == ',' || *s == '}') break; LAssert(*s != '\n'); s++; } } } if (s[-1] == ':') { LastDecl = s; } } else { s++; } break; } } } DeleteArray(CurClassDecl); if (Debug) { for (unsigned i=0; iType), def->File.Get(), def->Line, def->Name.Get()); } } return Defns.Length() > 0; } diff --git a/ResourceEditor/Makefile.linux b/ResourceEditor/Makefile.linux --- a/ResourceEditor/Makefile.linux +++ b/ResourceEditor/Makefile.linux @@ -1,386 +1,388 @@ #!/usr/bin/make # # This makefile generated by LgiIde # http://www.memecode.com/lgi.php # .SILENT : CC = gcc CPP = g++ Target = ./lgires ifndef Build Build = Debug endif +MakeDir := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) BuildDir = $(Build) Flags = -fPIC -w -fno-inline -fpermissive ifeq ($(Build),Debug) - Flags += -g -std=c++14 + Flags += -MMD -MP -g -std=c++14 Tag = d Defs = -D_DEBUG -DLINUX -D_REENTRANT -D_FILE_OFFSET_BITS=64 -DPOSIX Libs = \ -lmagic \ -lpthread \ -static-libgcc \ `pkg-config --libs gtk+-3.0` \ -llgi-gtk3$(Tag) \ -L../$(BuildDir) Inc = \ - -IResources \ + -I./Resources \ `pkg-config --cflags gtk+-3.0` \ -I../include/lgi/linux/Gtk \ -I../include/lgi/linux \ -I../include else - Flags += -s -Os -std=c++14 + Flags += -MMD -MP -s -Os -std=c++14 Defs = -DLINUX -D_REENTRANT -D_FILE_OFFSET_BITS=64 -DPOSIX Libs = \ -lmagic \ -lpthread \ -static-libgcc \ `pkg-config --libs gtk+-3.0` \ -llgi-gtk3$(Tag) \ -L../$(BuildDir) Inc = \ - -IResources \ + -I./Resources \ `pkg-config --cflags gtk+-3.0` \ -I../include/lgi/linux/Gtk \ -I../include/lgi/linux \ -I../include endif # Dependencies Source = Code/ShowLanguages.cpp \ Code/Search.cpp \ Code/LgiResApp.cpp \ Code/LgiRes_TableLayout.cpp \ Code/LgiRes_String.cpp \ Code/LgiRes_Menu.cpp \ Code/LgiRes_Dialog.cpp \ Code/LgiRes_Css.cpp \ Code/LgiRes_ControlTree.cpp \ ../src/common/Lgi/OptionsFile.cpp \ ../src/common/Lgi/LgiMain.cpp \ ../src/common/Lgi/DocApp.cpp \ ../src/common/Lgi/About.cpp \ ../src/common/Gdc2/Filters/Lzw.cpp \ ../src/common/Gdc2/Filters/Gif.cpp -SourceLst := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(Source))) -Objects := $(addprefix $(BuildDir)/,$(SourceLst)) -Deps := $(patsubst %.o,%.d,$(Objects)) +SourceC := $(filter %.c,$(Source)) +ObjectsC := $(SourceC:.c=.o) +SourceCpp := $(filter %.cpp,$(Source)) +ObjectsCpp := $(SourceCpp:.cpp=.o) +Objects := $(notdir $(ObjectsC) $(ObjectsCpp)) +Objects := $(addprefix $(BuildDir)/,$(Objects)) +Deps := $(patsubst %.o,%.d,$(Objects)) + +$(BuildDir)/%.o: %.c + mkdir -p $(@D) + echo $(notdir $<) [$(Build)] + $(CC) $(Inc) $(Flags) $(Defs) -c $< -o $@ + +$(BuildDir)/%.o: %.cpp + mkdir -p $(@D) + echo $(notdir $<) [$(Build)] + $(CPP) $(Inc) $(Flags) $(Defs) -c $< -o $@ # Target # Executable target $(Target) : ../$(BuildDir)/liblgi-gtk3$(Tag).so $(Objects) mkdir -p $(BuildDir) @echo Linking $(Target) [$(Build)]... $(CPP) -Wl,-export-dynamic,-R. -o \ $(Target) $(Objects) $(Libs) @echo Done. ../$(BuildDir)/liblgi-gtk3$(Tag).so : ../include/lgi/common/App.h \ ../include/lgi/common/Array.h \ ../include/lgi/common/AutoPtr.h \ ../include/lgi/common/Base64.h \ ../include/lgi/common/Bitmap.h \ ../include/lgi/common/Box.h \ ../include/lgi/common/Button.h \ ../include/lgi/common/CairoSurface.h \ ../include/lgi/common/Cancel.h \ ../include/lgi/common/Capabilities.h \ ../include/lgi/common/Charset.h \ ../include/lgi/common/CheckBox.h \ ../include/lgi/common/ClipBoard.h \ ../include/lgi/common/Colour.h \ ../include/lgi/common/ColourSpace.h \ ../include/lgi/common/Com.h \ ../include/lgi/common/Combo.h \ ../include/lgi/common/Containers.h \ ../include/lgi/common/Core.h \ ../include/lgi/common/Css.h \ ../include/lgi/common/CssTools.h \ ../include/lgi/common/CurrentTime.h \ ../include/lgi/common/DataDlg.h \ ../include/lgi/common/DateTime.h \ ../include/lgi/common/Dialog.h \ ../include/lgi/common/DisplayString.h \ ../include/lgi/common/DocView.h \ ../include/lgi/common/Dom.h \ ../include/lgi/common/DomFields.h \ ../include/lgi/common/DragAndDrop.h \ ../include/lgi/common/DropFiles.h \ ../include/lgi/common/Edit.h \ ../include/lgi/common/Error.h \ ../include/lgi/common/EventTargetThread.h \ ../include/lgi/common/File.h \ ../include/lgi/common/FileSelect.h \ ../include/lgi/common/Filter.h \ ../include/lgi/common/FindReplaceDlg.h \ ../include/lgi/common/Font.h \ ../include/lgi/common/FontCache.h \ ../include/lgi/common/FontSelect.h \ ../include/lgi/common/Gdc2.h \ ../include/lgi/common/GdcTools.h \ ../include/lgi/common/GdiLeak.h \ ../include/lgi/common/HashTable.h \ ../include/lgi/common/ImageList.h \ ../include/lgi/common/Input.h \ ../include/lgi/common/ItemContainer.h \ ../include/lgi/common/Json.h \ ../include/lgi/common/Layout.h \ ../include/lgi/common/Lgi.h \ ../include/lgi/common/LgiClasses.h \ ../include/lgi/common/LgiCommon.h \ ../include/lgi/common/LgiDefs.h \ ../include/lgi/common/LgiInc.h \ ../include/lgi/common/LgiInterfaces.h \ ../include/lgi/common/LgiMsgs.h \ ../include/lgi/common/LgiNetInc.h \ ../include/lgi/common/LgiRes.h \ ../include/lgi/common/LgiString.h \ ../include/lgi/common/LgiUiBase.h \ ../include/lgi/common/Library.h \ ../include/lgi/common/LibraryUtils.h \ ../include/lgi/common/List.h \ ../include/lgi/common/ListItemCheckBox.h \ ../include/lgi/common/ListItemRadioBtn.h \ ../include/lgi/common/LMallocArray.h \ ../include/lgi/common/Mail.h \ ../include/lgi/common/Matrix.h \ ../include/lgi/common/Mem.h \ ../include/lgi/common/Menu.h \ ../include/lgi/common/Message.h \ ../include/lgi/common/Mime.h \ ../include/lgi/common/Mru.h \ ../include/lgi/common/Mutex.h \ ../include/lgi/common/Net.h \ ../include/lgi/common/NetTools.h \ ../include/lgi/common/Notifications.h \ ../include/lgi/common/OAuth2.h \ ../include/lgi/common/OptionsFile.h \ ../include/lgi/common/Palette.h \ ../include/lgi/common/Panel.h \ ../include/lgi/common/Password.h \ ../include/lgi/common/Path.h \ ../include/lgi/common/PixelRops.h \ ../include/lgi/common/Point.h \ ../include/lgi/common/Popup.h \ ../include/lgi/common/PopupList.h \ + ../include/lgi/common/PopupNotification.h \ ../include/lgi/common/Printer.h \ ../include/lgi/common/Profile.h \ ../include/lgi/common/Progress.h \ ../include/lgi/common/ProgressDlg.h \ ../include/lgi/common/ProgressView.h \ ../include/lgi/common/Properties.h \ ../include/lgi/common/RadioGroup.h \ ../include/lgi/common/Range.h \ ../include/lgi/common/Rect.h \ ../include/lgi/common/RectF.h \ ../include/lgi/common/RefCount.h \ ../include/lgi/common/RegKey.h \ ../include/lgi/common/Res.h \ ../include/lgi/common/Rops.h \ ../include/lgi/common/ScrollBar.h \ ../include/lgi/common/SkinEngine.h \ ../include/lgi/common/Slider.h \ ../include/lgi/common/Splitter.h \ ../include/lgi/common/StatusBar.h \ ../include/lgi/common/Store3Defs.h \ ../include/lgi/common/Stream.h \ ../include/lgi/common/StringClass.h \ ../include/lgi/common/StringLayout.h \ ../include/lgi/common/StructuredIo.h \ ../include/lgi/common/StructuredLog.h \ ../include/lgi/common/SubProcess.h \ ../include/lgi/common/TableLayout.h \ ../include/lgi/common/TabView.h \ ../include/lgi/common/TextFile.h \ ../include/lgi/common/TextLabel.h \ ../include/lgi/common/TextLog.h \ ../include/lgi/common/TextView3.h \ ../include/lgi/common/Thread.h \ ../include/lgi/common/ThreadEvent.h \ ../include/lgi/common/Token.h \ ../include/lgi/common/ToolBar.h \ ../include/lgi/common/ToolTip.h \ ../include/lgi/common/TrayIcon.h \ ../include/lgi/common/Tree.h \ ../include/lgi/common/Undo.h \ ../include/lgi/common/Unicode.h \ ../include/lgi/common/UnicodeString.h \ ../include/lgi/common/UnrolledList.h \ ../include/lgi/common/Variant.h \ ../include/lgi/common/View.h \ ../include/lgi/common/Widgets.h \ ../include/lgi/common/Window.h \ ../include/lgi/common/XmlTree.h \ ../include/lgi/linux/Gtk/LgiOsClasses.h \ ../include/lgi/linux/Gtk/LgiOsDefs.h \ ../include/lgi/linux/Gtk/LgiWidget.h \ ../include/lgi/linux/Gtk/LgiWinManGlue.h \ ../include/lgi/linux/SymLookup.h \ ../include/lgi/mac/cocoa/LCocoaView.h \ ../include/lgi/mac/cocoa/LgiMac.h \ ../include/lgi/mac/cocoa/LgiOs.h \ ../include/lgi/mac/cocoa/LgiOsClasses.h \ ../include/lgi/mac/cocoa/LgiOsDefs.h \ ../include/lgi/mac/cocoa/ObjCWrapper.h \ ../include/lgi/mac/cocoa/SymLookup.h \ ../private/common/FontPriv.h \ ../private/common/ViewPriv.h \ ../private/linux/AppPriv.h \ ../src/common/Gdc2/15Bit.cpp \ ../src/common/Gdc2/16Bit.cpp \ ../src/common/Gdc2/24Bit.cpp \ ../src/common/Gdc2/32Bit.cpp \ ../src/common/Gdc2/8Bit.cpp \ ../src/common/Gdc2/Alpha.cpp \ ../src/common/Gdc2/Colour.cpp \ ../src/common/Gdc2/Filters/Filter.cpp \ ../src/common/Gdc2/Font/Charset.cpp \ ../src/common/Gdc2/Font/DisplayString.cpp \ ../src/common/Gdc2/Font/Font.cpp \ ../src/common/Gdc2/Font/FontSystem.cpp \ ../src/common/Gdc2/Font/FontType.cpp \ ../src/common/Gdc2/Font/StringLayout.cpp \ ../src/common/Gdc2/Font/TypeFace.cpp \ ../src/common/Gdc2/GdcCommon.cpp \ ../src/common/Gdc2/Path/Path.cpp \ ../src/common/Gdc2/Rect.cpp \ ../src/common/Gdc2/RopsCases.cpp \ ../src/common/Gdc2/Surface.cpp \ ../src/common/Gdc2/Tools/ColourReduce.cpp \ ../src/common/Gdc2/Tools/GdcTools.cpp \ ../src/common/General/Containers.cpp \ ../src/common/General/DateTime.cpp \ ../src/common/General/ExeCheck.cpp \ ../src/common/General/FileCommon.cpp \ ../src/common/General/Password.cpp \ ../src/common/General/Properties.cpp \ ../src/common/Hash/md5/md5.c \ ../src/common/Hash/md5/md5.h \ ../src/common/Hash/sha1/sha1.c \ ../src/common/Hash/sha1/sha1.h \ ../src/common/Lgi/Alert.cpp \ ../src/common/Lgi/AppCommon.cpp \ ../src/common/Lgi/Css.cpp \ ../src/common/Lgi/CssTools.cpp \ ../src/common/Lgi/DataDlg.cpp \ ../src/common/Lgi/DragAndDropCommon.cpp \ ../src/common/Lgi/FileSelect.cpp \ ../src/common/Lgi/FindReplace.cpp \ ../src/common/Lgi/FontSelect.cpp \ ../src/common/Lgi/GuiUtils.cpp \ ../src/common/Lgi/Input.cpp \ ../src/common/Lgi/LgiCommon.cpp \ ../src/common/Lgi/Library.cpp \ ../src/common/Lgi/LMsg.cpp \ ../src/common/Lgi/MemStream.cpp \ ../src/common/Lgi/MenuCommon.cpp \ ../src/common/Lgi/Mru.cpp \ ../src/common/Lgi/Mutex.cpp \ ../src/common/Lgi/Object.cpp \ ../src/common/Lgi/OptionsFile.cpp \ ../src/common/Lgi/Rand.cpp \ ../src/common/Lgi/Stream.cpp \ ../src/common/Lgi/SubProcess.cpp \ ../src/common/Lgi/ThreadCommon.cpp \ ../src/common/Lgi/ThreadEvent.cpp \ ../src/common/Lgi/ToolTip.cpp \ ../src/common/Lgi/TrayIcon.cpp \ ../src/common/Lgi/Variant.cpp \ ../src/common/Lgi/ViewCommon.cpp \ ../src/common/Lgi/WindowCommon.cpp \ ../src/common/Net/Base64.cpp \ ../src/common/Net/MDStringToDigest.cpp \ ../src/common/Net/Net.cpp \ ../src/common/Net/NetTools.cpp \ ../src/common/Net/Uri.cpp \ ../src/common/Resource/LgiRes.cpp \ ../src/common/Resource/Res.cpp \ ../src/common/Skins/Gel/Gel.cpp \ ../src/common/Text/DocView.cpp \ ../src/common/Text/String.cpp \ ../src/common/Text/TextView3.cpp \ ../src/common/Text/Token.cpp \ ../src/common/Text/Unicode.cpp \ ../src/common/Text/Utf8.cpp \ ../src/common/Text/XmlTree.cpp \ ../src/common/Widgets/Bitmap.cpp \ ../src/common/Widgets/Box.cpp \ ../src/common/Widgets/Button.cpp \ ../src/common/Widgets/CheckBox.cpp \ ../src/common/Widgets/Combo.cpp \ ../src/common/Widgets/Edit.cpp \ ../src/common/Widgets/ItemContainer.cpp \ ../src/common/Widgets/List.cpp \ ../src/common/Widgets/Panel.cpp \ ../src/common/Widgets/Popup.cpp \ ../src/common/Widgets/Progress.cpp \ ../src/common/Widgets/ProgressDlg.cpp \ ../src/common/Widgets/RadioGroup.cpp \ ../src/common/Widgets/ScrollBar.cpp \ ../src/common/Widgets/Slider.cpp \ ../src/common/Widgets/Splitter.cpp \ ../src/common/Widgets/StatusBar.cpp \ ../src/common/Widgets/TableLayout.cpp \ ../src/common/Widgets/TabView.cpp \ ../src/common/Widgets/TextLabel.cpp \ ../src/common/Widgets/ToolBar.cpp \ ../src/common/Widgets/Tree.cpp \ ../src/linux/General/File.cpp \ ../src/linux/General/Mem.cpp \ ../src/linux/General/ShowFileProp_Linux.cpp \ ../src/linux/Gtk/Gdc2.cpp \ ../src/linux/Gtk/LgiWidget.cpp \ ../src/linux/Gtk/MemDC.cpp \ ../src/linux/Gtk/PrintDC.cpp \ ../src/linux/Gtk/ScreenDC.cpp \ ../src/linux/Lgi/App.cpp \ ../src/linux/Lgi/ClipBoard.cpp \ ../src/linux/Lgi/DragAndDrop.cpp \ ../src/linux/Lgi/General.cpp \ ../src/linux/Lgi/Layout.cpp \ ../src/linux/Lgi/Menu.cpp \ ../src/linux/Lgi/Printer.cpp \ ../src/linux/Lgi/Thread.cpp \ ../src/linux/Lgi/View.cpp \ ../src/linux/Lgi/Widgets.cpp \ ../src/linux/Lgi/Window.cpp export Build=$(Build); \ - $(MAKE) -C .. -f Makefile.linux - -.SECONDEXPANSION: -$(Objects): $(BuildDir)/%.o: $$(wildcard %.c*) - mkdir -p $(@D) - @echo $(