From 7fb11b40878baa72ca9d71a656f7eb9b1af0f742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Mon, 20 Feb 2023 23:40:16 -0300 Subject: [PATCH] ecode: LSP fixes for Windows. Fixed console output on Windows. Closes SpartanJ/ecode#56. --- include/eepp/network/uri.hpp | 3 ++ include/eepp/system/sys.hpp | 5 +++ include/eepp/ui/doc/textdocument.hpp | 6 ++- .../eepp/ui/tools/uicodeeditorsplitter.hpp | 7 ++- src/eepp/network/uri.cpp | 21 +++++++-- src/eepp/system/sys.cpp | 44 +++++++++++++++++++ src/eepp/ui/doc/textdocument.cpp | 16 ++++++- src/eepp/ui/tools/uicodeeditorsplitter.cpp | 28 +++++++++--- src/tools/ecode/ecode.cpp | 9 +++- .../ecode/plugins/lsp/lspclientplugin.cpp | 6 +-- .../ecode/plugins/lsp/lspclientserver.cpp | 6 +-- .../plugins/lsp/lspclientservermanager.cpp | 10 ++--- src/tools/ecode/projectdirectorytree.cpp | 2 +- 13 files changed, 136 insertions(+), 27 deletions(-) diff --git a/include/eepp/network/uri.hpp b/include/eepp/network/uri.hpp index 90c05a8c0..42046cd56 100644 --- a/include/eepp/network/uri.hpp +++ b/include/eepp/network/uri.hpp @@ -152,6 +152,9 @@ class EE_API URI { /** @returns The path part of the URI. */ const std::string& getPath() const; + /* @returns The file system path of the URI. */ + std::string getFSPath() const; + /** @returns The last path segment. */ std::string getLastPathSegment() const; diff --git a/include/eepp/system/sys.hpp b/include/eepp/system/sys.hpp index 41ca22131..6ae9b9460 100644 --- a/include/eepp/system/sys.hpp +++ b/include/eepp/system/sys.hpp @@ -83,6 +83,11 @@ class EE_API Sys { * @return The executable file path, or an empty string if not found. */ static std::string which( const std::string& exeName, const std::vector& customSearchPaths = {} ); + + /* It will attach the console to the parent process console if any. Windows only function. + * Other platforms will do nothing. + */ + static bool windowAttachConsole(); }; }} // namespace EE::System diff --git a/include/eepp/ui/doc/textdocument.hpp b/include/eepp/ui/doc/textdocument.hpp index 97f329db0..c164302f2 100644 --- a/include/eepp/ui/doc/textdocument.hpp +++ b/include/eepp/ui/doc/textdocument.hpp @@ -395,7 +395,7 @@ class EE_API TextDocument { const std::string& getFilePath() const; - URI getURI() const; + const URI& getURI() const; const FileInfo& getFileInfo() const; @@ -488,6 +488,8 @@ class EE_API TextDocument { const std::string& getLoadingFilePath() const; + const URI& getLoadingFileURI() const; + void setSelection( const TextRanges& selection ); void resetSelection( const TextRanges& selection ); @@ -552,6 +554,8 @@ class EE_API TextDocument { UndoStack mUndoStack; std::string mFilePath; std::string mLoadingFilePath; + URI mFileURI; + URI mLoadingFileURI; FileInfo mFileRealPath; std::vector mLines; TextRanges mSelection; diff --git a/include/eepp/ui/tools/uicodeeditorsplitter.hpp b/include/eepp/ui/tools/uicodeeditorsplitter.hpp index 6526f6b1b..d0d921dcb 100644 --- a/include/eepp/ui/tools/uicodeeditorsplitter.hpp +++ b/include/eepp/ui/tools/uicodeeditorsplitter.hpp @@ -116,7 +116,10 @@ class EE_API UICodeEditorSplitter { UITabWidget* createEditorWithTabWidget( Node* parent, bool openCurEditor = true ); - UITab* isDocumentOpen( std::string path, bool checkOnlyInCurrentTabWidget = false, + UITab* isDocumentOpen( const std::string& path, bool checkOnlyInCurrentTabWidget = false, + bool checkOpeningDocuments = false ) const; + + UITab* isDocumentOpen( const URI& uri, bool checkOnlyInCurrentTabWidget = false, bool checkOpeningDocuments = false ) const; UICodeEditor* editorFromTab( UITab* tab ) const; @@ -177,6 +180,8 @@ class EE_API UICodeEditorSplitter { std::shared_ptr findDocFromPath( const std::string& path ); + std::shared_ptr UICodeEditorSplitter::findDocFromURI( const URI& uri ); + bool getHideTabBarOnSingleTab() const; void setHideTabBarOnSingleTab( bool hideTabBarOnSingleTab ); diff --git a/src/eepp/network/uri.cpp b/src/eepp/network/uri.cpp index d4b84b017..dd90d91ee 100644 --- a/src/eepp/network/uri.cpp +++ b/src/eepp/network/uri.cpp @@ -553,9 +553,13 @@ unsigned short URI::getWellKnownPort() const { void URI::parse( const std::string& _uri ) { std::string uri( _uri ); // Is a local path without hostname but it's correctly formatted? - if ( String::startsWith( uri, "file://" ) && uri.size() >= 9 && uri[7] != '/' && - uri[8] == ':' ) { - uri.insert( uri.begin() + 7, '/' ); + if ( String::startsWith( uri, "file://" ) && uri.size() >= 9 ) { + if ( uri[7] != '/' && uri[8] == ':' ) { + uri[7] = std::tolower( uri[7] ); + uri.insert( uri.begin() + 7, '/' ); + } else if ( uri.size() >= 10 && uri[9] == ':' && uri[7] == '/' ) { + uri[8] = std::tolower( uri[8] ); + } } String::replaceAll( uri, "\\", "/" ); #else @@ -738,6 +742,17 @@ void URI::buildPath( const std::vector& segments, bool leadingSlash mPath += '/'; } +std::string URI::getFSPath() const { +#if EE_PLATFORM == EE_PLATFORM_WIN + if ( mScheme == "file" && !mPath.empty() && mPath[0] == '/' ) { + std::string path = mPath.substr( 1 ); + String::replaceAll( path, "/", "\\" ); + return path; + } +#endif + return mPath; +} + bool URI::operator<( const URI& url ) const { int cmp; cmp = mScheme.compare( url.mScheme ); diff --git a/src/eepp/system/sys.cpp b/src/eepp/system/sys.cpp index 48fb686db..4ef22c066 100644 --- a/src/eepp/system/sys.cpp +++ b/src/eepp/system/sys.cpp @@ -7,6 +7,7 @@ #include #include #include +#include // This taints the System module! #if EE_PLATFORM == EE_PLATFORM_ANDROID @@ -1073,4 +1074,47 @@ std::string Sys::which( const std::string& exeName, return ""; } +#if EE_PLATFORM == EE_PLATFORM_WIN +static ULONG_PTR GetParentProcessId() { + ULONG_PTR pbi[6]; + ULONG ulSize = 0; + LONG( WINAPI * NtQueryInformationProcess ) + ( HANDLE ProcessHandle, ULONG ProcessInformationClass, PVOID ProcessInformation, + ULONG ProcessInformationLength, PULONG ReturnLength ); + *(FARPROC*)&NtQueryInformationProcess = + GetProcAddress( LoadLibraryA( "NTDLL.DLL" ), "NtQueryInformationProcess" ); + if ( NtQueryInformationProcess ) { + if ( NtQueryInformationProcess( GetCurrentProcess(), 0, &pbi, sizeof( pbi ), &ulSize ) >= + 0 && + ulSize == sizeof( pbi ) ) + return pbi[5]; + } + return (ULONG_PTR)-1; +} +#endif + +bool Sys::windowAttachConsole() { +#if EE_PLATFORM == EE_PLATFORM_WIN + ULONG_PTR ppid = GetParentProcessId(); + if ( ppid == (ULONG_PTR)-1 ) { + return false; + } else { + AttachConsole( ppid ); + } + + freopen( "CONIN$", "r", stdin ); + freopen( "CONOUT$", "w", stdout ); + freopen( "CONOUT$", "w", stderr ); + + std::cout.clear(); + std::cerr.clear(); + std::cin.clear(); + + std::wcout.clear(); + std::wcerr.clear(); + std::wcin.clear(); +#endif + return true; +} + }} // namespace EE::System diff --git a/src/eepp/ui/doc/textdocument.cpp b/src/eepp/ui/doc/textdocument.cpp index cfb7aa4ee..cb417a963 100644 --- a/src/eepp/ui/doc/textdocument.cpp +++ b/src/eepp/ui/doc/textdocument.cpp @@ -62,6 +62,7 @@ bool TextDocument::isUntitledEmpty() const { void TextDocument::reset() { mFilePath = mDefaultFileName; + mFileURI = URI( "file://" + mFilePath ); mFileRealPath = FileInfo(); mSelection.clear(); mSelection.push_back( { { 0, 0 }, { 0, 0 } } ); @@ -311,6 +312,7 @@ bool TextDocument::getBOM() const { void TextDocument::notifyDocumentMoved( const std::string& path ) { mFilePath = path; + mFileURI = URI( "file://" + mFilePath ); mFileRealPath = FileInfo::isLink( mFilePath ) ? FileInfo( FileInfo( mFilePath ).linksTo() ) : FileInfo( mFilePath ); notifyDocumentMoved(); @@ -343,6 +345,11 @@ const std::string& TextDocument::getLoadingFilePath() const { return mLoadingFilePath; } +const URI& TextDocument::getLoadingFileURI() const { + Lock l( mLoadingFilePathMutex ); + return mLoadingFileURI; +} + TextDocument::LoadStatus TextDocument::loadFromFile( const std::string& path ) { mLoading = true; if ( !FileSystem::fileExists( path ) && PackManager::instance()->isFallbackToPacksActive() ) { @@ -351,6 +358,7 @@ TextDocument::LoadStatus TextDocument::loadFromFile( const std::string& path ) { if ( NULL != pack ) { mFilePath = pathFix; mFileRealPath = FileInfo(); + mFileURI = URI( "file://" + mFilePath ); return loadFromPack( pack, pathFix ); } } @@ -358,6 +366,7 @@ TextDocument::LoadStatus TextDocument::loadFromFile( const std::string& path ) { IOStreamFile file( path, "rb" ); auto ret = loadFromStream( file, path, true ); mFilePath = path; + mFileURI = URI( "file://" + mFilePath ); mFileRealPath = FileInfo::isLink( mFilePath ) ? FileInfo( FileInfo( mFilePath ).linksTo() ) : FileInfo( mFilePath ); resetSyntax(); @@ -374,6 +383,7 @@ bool TextDocument::loadAsyncFromFile( const std::string& path, std::shared_ptrrun( [this, path, onLoaded] { @@ -384,6 +394,7 @@ bool TextDocument::loadAsyncFromFile( const std::string& path, std::shared_ptrgetOwnedWidget()->asType(); - if ( editor->getDocument().getFilePath() == path || - ( checkOpeningDocuments && editor->getDocument().getLoadingFilePath() == path ) ) { + if ( editor->getDocument().getURI() == uri || + ( checkOpeningDocuments && editor->getDocument().getLoadingFilePath() == uri.getFSPath() ) ) { return tab; } } @@ -593,9 +597,9 @@ UITab* UICodeEditorSplitter::isDocumentOpen( std::string path, bool checkOnlyInC continue; UICodeEditor* editor = tab->getOwnedWidget()->asType(); - if ( editor->getDocument().getFilePath() == path || + if ( editor->getDocument().getURI() == uri || ( checkOpeningDocuments && - editor->getDocument().getLoadingFilePath() == path ) ) { + editor->getDocument().getLoadingFilePath() == uri.getFSPath() ) ) { return tab; } } @@ -727,6 +731,16 @@ void UICodeEditorSplitter::forEachDocStoppable( std::function UICodeEditorSplitter::findDocFromURI( const URI& uri ) { + std::unordered_set> docs; + forEachEditor( [&]( UICodeEditor* editor ) { docs.insert( editor->getDocumentRef() ); } ); + for ( const auto& doc : docs ) { + if ( doc->getURI() == uri ) + return doc; + } + return {}; +} + std::shared_ptr UICodeEditorSplitter::findDocFromPath( const std::string& path ) { std::unordered_set> docs; forEachEditor( [&]( UICodeEditor* editor ) { docs.insert( editor->getDocumentRef() ); } ); diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index ed298329b..fbd2fcdc9 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -2050,7 +2050,7 @@ void App::renameFile( const FileInfo& file ) { msgBox->getTextInput()->setText( file.getFileName() ); msgBox->addEventListener( Event::OnConfirm, [&, file, msgBox]( const Event* ) { auto newFilePath( getNewFilePath( file, msgBox, false ) ); - if ( !FileSystem::fileExists( newFilePath ) ) { + if ( !FileSystem::fileExists( newFilePath ) || file.getFileName() != msgBox->getTextInput()->getText() ) { try { std::string fpath( file.getFilepath() ); if ( file.isDirectory() ) @@ -2371,6 +2371,8 @@ void App::loadFolder( const std::string& path ) { closeEditors(); std::string rpath( FileSystem::getRealPath( path ) ); + FileSystem::dirAddSlashAtEnd( rpath ); + mCurrentProject = rpath; mPluginManager->setWorkspaceFolder( rpath ); @@ -2451,6 +2453,7 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe loadConfig( logLevel, currentDisplay->getSize(), health ); if ( health ) { + Sys::windowAttachConsole(); FeaturesHealth::doHealth( mPluginManager.get(), healthLang, healthFormat ); return; } @@ -3151,19 +3154,23 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) { try { parser.ParseCLI( Sys::parseArguments( argc, argv ) ); } catch ( const args::Help& ) { + Sys::windowAttachConsole(); std::cout << parser; return EXIT_SUCCESS; } catch ( const args::ParseError& e ) { + Sys::windowAttachConsole(); std::cerr << e.what() << std::endl; std::cerr << parser; return EXIT_FAILURE; } catch ( args::ValidationError& e ) { + Sys::windowAttachConsole(); std::cerr << e.what() << std::endl; std::cerr << parser; return EXIT_FAILURE; } if ( version.Get() ) { + Sys::windowAttachConsole(); std::cout << ecode::Version::getVersionFullName() << '\n'; return EXIT_SUCCESS; } diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp index 4e409dc45..957cf79b4 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -61,7 +61,7 @@ class LSPLocationModel : public Model { FileSystem::dirAddSlashAtEnd( workspaceFolder ); for ( const auto& loc : locs ) { - std::string display = loc.uri.getPath(); + std::string display = loc.uri.getFSPath(); FileSystem::filePathRemoveBasePath( workspaceFolder, display ); display += " - L" + String::toString( loc.range.start().line() ); mLocs.push_back( { loc, display } ); @@ -250,9 +250,9 @@ PluginRequestHandle LSPClientPlugin::processDocumentFormatting( const PluginMess bool LSPClientPlugin::processDocumentFormattingResponse( const URI& uri, std::vector edits ) { - auto doc = mManager->getSplitter()->findDocFromPath( uri.getPath() ); + auto doc = mManager->getSplitter()->findDocFromURI( uri ); if ( !doc ) { - auto pair = mManager->getSplitter()->loadFileFromPathInNewTab( uri.getPath() ); + auto pair = mManager->getSplitter()->loadFileFromPathInNewTab( uri.getFSPath() ); if ( pair.first == nullptr || pair.second == nullptr || !pair.second->getDocumentRef() ) return false; doc = pair.second->getDocumentRef(); diff --git a/src/tools/ecode/plugins/lsp/lspclientserver.cpp b/src/tools/ecode/plugins/lsp/lspclientserver.cpp index 2980966af..4b3118dbc 100644 --- a/src/tools/ecode/plugins/lsp/lspclientserver.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientserver.cpp @@ -924,7 +924,7 @@ void LSPClientServer::initialize() { } } std::string rootUri = rootPath.toString(); - params["rootPath"] = rootPath.getPath(); + params["rootPath"] = rootPath.getFSPath(); params["rootUri"] = rootUri; params["workspaceFolders"] = toJson( { LSPWorkspaceFolder{ rootUri, FileSystem::fileNameFromPath( rootUri ) } } ); @@ -1539,7 +1539,7 @@ LSPClientServer::documentImplementation( const URI& document, const TextPosition } static std::vector switchHeaderSourceName( const URI& uri ) { - std::string basePath( "file://" + FileSystem::fileRemoveExtension( uri.getPath() ) ); + std::string basePath( "file://" + FileSystem::fileRemoveExtension( uri.getFSPath() ) ); if ( FileSystem::fileExtension( uri.getPath() ) == "cpp" ) { return { basePath + ".hpp", basePath + ".h" }; } else if ( FileSystem::fileExtension( uri.getPath() ) == "hpp" ) { @@ -1560,7 +1560,7 @@ LSPClientServer::LSPRequestHandle LSPClientServer::switchSourceHeader( const URI for ( const auto& uri : uris ) { if ( res.is_string() && ( uri.empty() || FileSystem::fileNameFromPath( res.get() ) == - FileSystem::fileNameFromPath( uri.getPath() ) ) ) { + FileSystem::fileNameFromPath( uri.getFSPath() ) ) ) { mManager->goToLocation( { res.get(), TextRange() } ); break; } else if ( !uri.empty() ) { diff --git a/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp b/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp index 2ffd60ba4..1c0728d26 100644 --- a/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp @@ -127,9 +127,9 @@ void LSPClientServerManager::goToLocation( const LSPLocation& loc ) { if ( nullptr == splitter ) return; splitter->getUISceneNode()->runOnMainThread( [this, splitter, loc]() { - UITab* tab = splitter->isDocumentOpen( loc.uri.toString() ); + UITab* tab = splitter->isDocumentOpen( loc.uri ); if ( !tab ) { - std::string path( loc.uri.getPath() ); + std::string path( loc.uri.getFSPath() ); FileInfo fileInfo( path ); if ( fileInfo.exists() && fileInfo.isRegularFile() ) { splitter->loadAsyncFileFromPathInNewTab( @@ -289,10 +289,10 @@ void LSPClientServerManager::sendSymbolReferenceBroadcast( const std::vector res; for ( auto& r : resp ) { - auto& rd = res[r.uri.getPath()]; + auto& rd = res[r.uri.getFSPath()]; if ( rd.file.empty() ) - rd.file = r.uri.getPath(); - auto curDoc = mPluginManager->getSplitter()->findDocFromPath( r.uri.getPath() ); + rd.file = r.uri.getFSPath(); + auto curDoc = mPluginManager->getSplitter()->findDocFromURI( r.uri ); if ( !curDoc ) continue; diff --git a/src/tools/ecode/projectdirectorytree.cpp b/src/tools/ecode/projectdirectorytree.cpp index 777772fd5..b385a59d7 100644 --- a/src/tools/ecode/projectdirectorytree.cpp +++ b/src/tools/ecode/projectdirectorytree.cpp @@ -438,7 +438,7 @@ PluginRequestHandle ProjectDirectoryTree::processMessage( const PluginMessage& m std::vector expectedNames; std::vector tentativePaths; for ( const auto& turi : juris ) { - std::string path( URI( turi.get() ).getPath() ); + std::string path( URI( turi.get() ).getFSPath() ); tentativePaths.emplace_back( path ); expectedNames.emplace_back( FileSystem::fileNameFromPath( path ) ); }