diff --git a/CodeLite/fileutils.cpp b/CodeLite/fileutils.cpp index 36a77860a6..fce8786cff 100644 --- a/CodeLite/fileutils.cpp +++ b/CodeLite/fileutils.cpp @@ -62,6 +62,9 @@ #include #include + +static bool bRealPathModeResolveSymlinks = true; + thread_local std::unordered_set VALID_CHARS = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', @@ -595,10 +598,10 @@ unsigned int FileUtils::UTF8Length(const wchar_t* uptr, unsigned int tlen) } // This is readlink on steroids: it also makes-absolute, and dereferences any symlinked dirs in the path -wxString FileUtils::RealPath(const wxString& filepath) +wxString FileUtils::RealPath(const wxString& filepath, bool forced) { #if defined(__WXGTK__) || defined(__WXOSX__) - if (!filepath.empty()) { + if (!filepath.empty() && (forced || bRealPathModeResolveSymlinks)) { #if defined(__FreeBSD__) || defined(__WXOSX__) wxStructStat stbuff; if ((::wxLstat(filepath, &stbuff) != 0) || !S_ISLNK(stbuff.st_mode)) { @@ -617,6 +620,17 @@ wxString FileUtils::RealPath(const wxString& filepath) return filepath; } +bool FileUtils::RealPathGetModeResolveSymlinks(void) +{ + return bRealPathModeResolveSymlinks; +} + +void FileUtils::RealPathSetModeResolveSymlinks(bool resolveSymlinks) +{ + bRealPathModeResolveSymlinks = resolveSymlinks; +} + + std::string FileUtils::ToStdString(const wxString& str) { return StringUtils::ToStdString(str); } bool FileUtils::ReadBufferFromFile(const wxFileName& fn, wxString& data, size_t bufferSize) diff --git a/CodeLite/fileutils.h b/CodeLite/fileutils.h index 618e0fed57..d7d1e7a6a9 100644 --- a/CodeLite/fileutils.h +++ b/CodeLite/fileutils.h @@ -247,7 +247,9 @@ class WXDLLIMPEXP_CL FileUtils /** * @brief (on Linux) makes-absolute filepath, and dereferences it and any symlinked dirs in the path */ - static wxString RealPath(const wxString& filepath); + static wxString RealPath(const wxString& filepath, bool forced=false); + static bool RealPathGetModeResolveSymlinks(void); + static void RealPathSetModeResolveSymlinks(bool resolveSymlinks); /** * @brief convert string into std::string diff --git a/LiteEditor/editorsettingsdockingwidows.cpp b/LiteEditor/editorsettingsdockingwidows.cpp index 155da73d13..466a47b76a 100644 --- a/LiteEditor/editorsettingsdockingwidows.cpp +++ b/LiteEditor/editorsettingsdockingwidows.cpp @@ -103,4 +103,8 @@ EditorSettingsDockingWindows::EditorSettingsDockingWindows(wxWindow* parent, Opt AddProperty(_("Find next/Find previous actions override search string with current selection (like Find next at caret/prev at caret)"), m_options->GetFindNextOrPreviousUseSelection(), UPDATE_BOOL_CB(SetFindNextOrPreviousUseSelection)); + AddHeader(_("File path handling")); + AddProperty(_("Resolve symlinks in file paths"), + m_options->GetRealPathResolveSymlinks(), + UPDATE_BOOL_CB(SetRealPathResolveSymlinks)); } diff --git a/LiteEditor/mainbook.cpp b/LiteEditor/mainbook.cpp index 6db5cb2385..277cdf9900 100644 --- a/LiteEditor/mainbook.cpp +++ b/LiteEditor/mainbook.cpp @@ -258,7 +258,7 @@ void MainBook::OnProjectFileAdded(clCommandEvent& e) for (size_t i = 0; i < files.GetCount(); i++) { clEditor* editor = FindEditor(files.Item(i)); if (editor) { - wxString fileName = CLRealPath(editor->GetFileName().GetFullPath()); + wxString fileName = FileUtils::RealPath(editor->GetFileName().GetFullPath()); if (files.Index(fileName) != wxNOT_FOUND) { editor->SetProject(ManagerST::Get()->GetProjectNameByFile(fileName)); } @@ -272,7 +272,7 @@ void MainBook::OnProjectFileRemoved(clCommandEvent& e) const wxArrayString& files = e.GetStrings(); for (size_t i = 0; i < files.GetCount(); ++i) { clEditor* editor = FindEditor(files.Item(i)); - if (editor && files.Index(CLRealPath(editor->GetFileName().GetFullPath())) != wxNOT_FOUND) { + if (editor && files.Index(FileUtils::RealPath(editor->GetFileName().GetFullPath())) != wxNOT_FOUND) { editor->SetProject(wxEmptyString); } } @@ -451,7 +451,7 @@ int MainBook::FindEditorIndexByFullPath(const wxString& fullpath) { #ifdef __WXGTK__ // On gtk either fileName or the editor filepath (or both) may be (or their paths contain) symlinks - wxString fileNameDest = CLRealPath(fullpath); + wxString fileNameDest = FileUtils::RealPath(fullpath, true); #endif for (size_t i = 0; i < m_book->GetPageCount(); ++i) { @@ -465,7 +465,7 @@ int MainBook::FindEditorIndexByFullPath(const wxString& fullpath) } } else { // local path - wxString unixStyleFile(CLRealPath(editor->GetFileName().GetFullPath())); + wxString unixStyleFile(FileUtils::RealPath(editor->GetFileName().GetFullPath())); wxString nativeFile(unixStyleFile); #ifdef __WXMSW__ unixStyleFile.Replace(wxT("\\"), wxT("/")); @@ -485,7 +485,7 @@ int MainBook::FindEditorIndexByFullPath(const wxString& fullpath) #if defined(__WXGTK__) // Try again, dereferencing the editor fpath - wxString editorDest = CLRealPath(unixStyleFile); + wxString editorDest = FileUtils::RealPath(unixStyleFile, true); if (editorDest.Cmp(fullpath) == 0 || editorDest.Cmp(fileNameDest) == 0) { return i; } @@ -509,12 +509,13 @@ wxWindow* MainBook::FindPage(const wxString& text) { for (size_t i = 0; i < m_book->GetPageCount(); i++) { clEditor* editor = dynamic_cast(m_book->GetPage(i)); - if (editor && CLRealPath(editor->GetFileName().GetFullPath()).CmpNoCase(text) == 0) { + if (editor && FileUtils::RealPath(editor->GetFileName().GetFullPath()).CmpNoCase(text) == 0) { return editor; } - if (m_book->GetPageText(i) == text) + if (m_book->GetPageText(i) == text) { return m_book->GetPage(i); + } } return NULL; } @@ -620,7 +621,14 @@ clEditor* MainBook::OpenFile(const wxString& file_name, int bmp /*= wxNullBitmap*/, const wxString& tooltip /* wxEmptyString */) { - wxFileName fileName(CLRealPath(file_name)); + wxFileName fileName(FileUtils::RealPath(file_name)); + + if (fileName.IsRelative()) { + if (clWorkspaceManager::Get().IsWorkspaceOpened()) { + wxFileName wsPath = clWorkspaceManager::Get().GetWorkspace()->GetDir(); + fileName.MakeAbsolute(wsPath.GetFullPath()); + } + } fileName.MakeAbsolute(); #ifdef __WXMSW__ @@ -1220,7 +1228,7 @@ bool MainBook::DoSelectPage(wxWindow* win) } else { wxCommandEvent event(wxEVT_ACTIVE_EDITOR_CHANGED); - event.SetString(CLRealPath(editor->GetFileName().GetFullPath())); + event.SetString(FileUtils::RealPath(editor->GetFileName().GetFullPath())); EventNotifier::Get()->AddPendingEvent(event); } return true; @@ -1737,7 +1745,7 @@ WelcomePage* MainBook::GetWelcomePage(bool createIfMissing) clEditor* MainBook::OpenFileAsync(const wxString& file_name, std::function&& callback) { - wxString real_path = CLRealPath(file_name); + wxString real_path = FileUtils::RealPath(file_name, true); auto editor = FindEditor(real_path); if (editor) { push_callback(std::move(callback), real_path); @@ -1748,7 +1756,7 @@ clEditor* MainBook::OpenFileAsync(const wxString& file_name, std::functionSetSelection(index); } } else { - editor = OpenFile(real_path); + editor = OpenFile(file_name); if (editor) { push_callback(std::move(callback), real_path); } @@ -1813,11 +1821,12 @@ void MainBook::OnIdle(wxIdleEvent& event) auto editor = GetActiveEditor(); CHECK_PTR_RET(editor); - execute_callbacks_for_file(CLRealPath(editor->GetFileName().GetFullPath())); + execute_callbacks_for_file(FileUtils::RealPath(editor->GetFileName().GetFullPath(), true)); } void MainBook::OnEditorModified(clCommandEvent& event) { event.Skip(); } void MainBook::OnEditorSaved(clCommandEvent& event) { event.Skip(); } -void MainBook::OnSessionLoaded(clCommandEvent& event) { event.Skip(); } \ No newline at end of file +void MainBook::OnSessionLoaded(clCommandEvent& event) { event.Skip(); } + diff --git a/Plugin/globals.cpp b/Plugin/globals.cpp index 100970911d..f496da8143 100644 --- a/Plugin/globals.cpp +++ b/Plugin/globals.cpp @@ -928,7 +928,7 @@ wxFileName wxReadLink(const wxFileName& filename) if (wxIsFileSymlink(filename)) { #if defined(__WXGTK__) // Use 'realpath' on Linux, otherwise this breaks on relative symlinks, and (untested) on symlinks-to-symlinks - return wxFileName(CLRealPath(filename.GetFullPath())); + return wxFileName(FileUtils::RealPath(filename.GetFullPath(), true)); #else // OSX wxFileName realFileName; diff --git a/Plugin/optionsconfig.cpp b/Plugin/optionsconfig.cpp index 2e76c58b5e..7b0ff9f7d4 100644 --- a/Plugin/optionsconfig.cpp +++ b/Plugin/optionsconfig.cpp @@ -115,6 +115,7 @@ OptionsConfig::OptionsConfig(wxXmlNode* node) , m_dontAutoFoldResults(true) , m_dontOverrideSearchStringWithSelection(false) , m_findNextOrPreviousUseSelection(true) + , m_realPathResolveSymlinks(true) , m_showDebugOnRun(true) , m_caretUseCamelCase(true) , m_wordWrap(false) @@ -211,6 +212,9 @@ OptionsConfig::OptionsConfig(wxXmlNode* node) node, wxT("DontOverrideSearchStringWithSelection"), m_dontOverrideSearchStringWithSelection); m_findNextOrPreviousUseSelection = XmlUtils::ReadBool( node, wxT("FindNextOrPreviousUseSelection"), m_findNextOrPreviousUseSelection); + m_realPathResolveSymlinks = XmlUtils::ReadBool( + node, wxT("RealPathResolveSymlinks"), m_realPathResolveSymlinks); + FileUtils::RealPathSetModeResolveSymlinks(m_realPathResolveSymlinks); m_showDebugOnRun = XmlUtils::ReadBool(node, wxT("ShowDebugOnRun"), m_showDebugOnRun); m_caretUseCamelCase = XmlUtils::ReadBool(node, wxT("m_caretUseCamelCase"), m_caretUseCamelCase); m_wordWrap = XmlUtils::ReadBool(node, wxT("m_wordWrap"), m_wordWrap); @@ -315,6 +319,8 @@ wxXmlNode* OptionsConfig::ToXml() const BoolToString(m_dontOverrideSearchStringWithSelection)); n->AddAttribute(wxT("FindNextOrPreviousUseSelection"), BoolToString(m_findNextOrPreviousUseSelection)); + n->AddAttribute(wxT("RealPathResolveSymlinks"), + BoolToString(m_realPathResolveSymlinks)); n->AddAttribute(wxT("ShowDebugOnRun"), BoolToString(m_showDebugOnRun)); n->AddAttribute(wxT("ConsoleCommand"), m_programConsoleCommand); n->AddAttribute(wxT("EOLMode"), m_eolMode); diff --git a/Plugin/optionsconfig.h b/Plugin/optionsconfig.h index bdbb8d1fc0..9e9dba7e6c 100644 --- a/Plugin/optionsconfig.h +++ b/Plugin/optionsconfig.h @@ -30,6 +30,7 @@ #include "clEditorConfig.h" #include "codelite_exports.h" #include "configuration_object.h" +#include "fileutils.h" #include #include @@ -142,6 +143,7 @@ class WXDLLIMPEXP_SDK OptionsConfig : public ConfObject bool m_dontAutoFoldResults; bool m_dontOverrideSearchStringWithSelection; bool m_findNextOrPreviousUseSelection; + bool m_realPathResolveSymlinks; bool m_showDebugOnRun; bool m_caretUseCamelCase; bool m_dontTrimCaretLine; @@ -232,6 +234,12 @@ class WXDLLIMPEXP_SDK OptionsConfig : public ConfObject m_findNextOrPreviousUseSelection = findNextOrPreviousUseSelection; } bool GetFindNextOrPreviousUseSelection() const { return m_findNextOrPreviousUseSelection; } + void SetRealPathResolveSymlinks(bool realPathResolveSymlinks) + { + m_realPathResolveSymlinks = realPathResolveSymlinks; + FileUtils::RealPathSetModeResolveSymlinks(m_realPathResolveSymlinks); + } + bool GetRealPathResolveSymlinks() const { return m_realPathResolveSymlinks; } void SetShowDebugOnRun(bool showDebugOnRun) { this->m_showDebugOnRun = showDebugOnRun; } bool GetShowDebugOnRun() const { return m_showDebugOnRun; } bool GetDisableSemicolonShift() const { return m_disableSemicolonShift; }