diff --git a/include/eepp/system/process.hpp b/include/eepp/system/process.hpp index 7ec37c1fd..e9dc62f8f 100644 --- a/include/eepp/system/process.hpp +++ b/include/eepp/system/process.hpp @@ -245,6 +245,7 @@ class EE_API Process { bool mIsAsync{ false }; bool mKilling{ false }; size_t mBufferSize{ 131072 }; + std::string mCmdLine; std::thread mStdOutThread; std::thread mStdErrThread; Mutex mStdInMutex; diff --git a/include/eepp/window/clipboard.hpp b/include/eepp/window/clipboard.hpp index 594e31b8c..6302794bd 100644 --- a/include/eepp/window/clipboard.hpp +++ b/include/eepp/window/clipboard.hpp @@ -21,6 +21,9 @@ class EE_API Clipboard { /** @return The parent window of the clipboard */ EE::Window::Window* getWindow() const; + /** @return True if primary selection is available */ + virtual bool hasPrimarySelection() const { return false; } + /** @return The Clipboard Primary Selection Text if available */ virtual std::string getPrimarySelectionText() { return ""; } diff --git a/src/eepp/core/string.cpp b/src/eepp/core/string.cpp index 685888c2e..7968b5f66 100644 --- a/src/eepp/core/string.cpp +++ b/src/eepp/core/string.cpp @@ -950,6 +950,8 @@ std::string String::join( const std::vector& strArray, const Int8& if ( s > 0 ) { for ( size_t i = 0; i < s; i++ ) { + if ( strArray[i] == nullptr ) + continue; str += strArray[i]; if ( joinchar >= 0 && ( i != s - 1 || appendLastJoinChar ) ) { diff --git a/src/eepp/graphics/fonttruetype.cpp b/src/eepp/graphics/fonttruetype.cpp index dc0db762a..de36ab4ba 100644 --- a/src/eepp/graphics/fonttruetype.cpp +++ b/src/eepp/graphics/fonttruetype.cpp @@ -862,7 +862,7 @@ Float FontTrueType::getLineSpacing( unsigned int characterSize ) const { Float FontTrueType::getGlyphTopOffset( unsigned int characterSize ) const { FT_Face face = static_cast( mFace ); - return FT_IS_SCALABLE( face ) ? characterSize : getAscent( characterSize ); + return FT_IS_SCALABLE( face ) || mIsColorEmojiFont ? characterSize : getAscent( characterSize ); } Float FontTrueType::getAscent( unsigned int characterSize ) const { diff --git a/src/eepp/system/process.cpp b/src/eepp/system/process.cpp index 78a20d9d2..c536f5443 100644 --- a/src/eepp/system/process.cpp +++ b/src/eepp/system/process.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -180,6 +181,7 @@ bool Process::create( const std::string& command, const std::vector } envStrings.push_back( NULL ); + mCmdLine = rcommand.empty() ? command : rcommand; auto ret = 0 == subprocess_create_ex( strings.data(), options, envStrings.data(), !workingDirectory.empty() ? workingDirectory.c_str() @@ -208,6 +210,7 @@ bool Process::create( const std::string& command, const std::vector for ( size_t i = 0; i < cmdArr.size(); ++i ) strings.push_back( cmdArr[i].c_str() ); strings.push_back( NULL ); + mCmdLine = rcommand.empty() ? command : rcommand; auto ret = 0 == subprocess_create_ex( strings.data(), options, nullptr, @@ -396,6 +399,7 @@ void Process::startAsyncRead( ReadFn readStdOut, ReadFn readStdErr ) { eeASSERT( mProcess != nullptr ); mReadStdOutFn = readStdOut; mReadStdErrFn = readStdErr; + Log::info( "Process::startAsyncRead called for command: %s", mCmdLine ); #if EE_PLATFORM == EE_PLATFORM_WIN void* stdOutFd = SUBPROCESS_PTR_CAST( void*, _get_osfhandle( _fileno( PROCESS_PTR->stdout_file ) ) ); @@ -403,6 +407,7 @@ void Process::startAsyncRead( ReadFn readStdOut, ReadFn readStdErr ) { SUBPROCESS_PTR_CAST( void*, _get_osfhandle( _fileno( PROCESS_PTR->stderr_file ) ) ); if ( stdOutFd ) { mStdOutThread = std::thread( [this, stdOutFd]() { + Log::info( "Process::startAsyncRead thread started for command: %s", mCmdLine ); unsigned n; std::string buffer; buffer.resize( mBufferSize ); @@ -438,28 +443,66 @@ void Process::startAsyncRead( ReadFn readStdOut, ReadFn readStdErr ) { } #elif defined( EE_PLATFORM_POSIX ) mStdOutThread = std::thread( [this] { + Log::info( "Process::startAsyncRead thread started for command: %s", mCmdLine ); auto stdOutFd = fileno( PROCESS_PTR->stdout_file ); auto stdErrFd = PROCESS_PTR->stderr_file ? fileno( PROCESS_PTR->stderr_file ) : 0; std::vector pollfds; std::bitset<2> fdIsStdOut; if ( stdOutFd ) { fdIsStdOut.set( pollfds.size() ); - pollfds.emplace_back(); - pollfds.back().fd = - fcntl( stdOutFd, F_SETFL, fcntl( stdOutFd, F_GETFL ) | O_NONBLOCK ) == 0 ? stdOutFd - : -1; + pollfds.emplace_back(); // Get current flags + int currentFlags = fcntl( stdOutFd, F_GETFL ); + if ( currentFlags == -1 ) { + pollfds.back().fd = -1; // Invalid FD + Log::error( "Process::startAsyncRead %s Failed to get flags for stdout fd", + mCmdLine ); + } else { + // Set non-blocking + if ( fcntl( stdOutFd, F_SETFL, currentFlags | O_NONBLOCK ) == 0 ) { + pollfds.back().fd = stdOutFd; + } else { + pollfds.back().fd = -1; + Log::error( "Process::startAsyncRead %s Failed to set O_NONBLOCK on stdout", + mCmdLine ); + } + } pollfds.back().events = POLLIN; + } else { + Log::error( "Process::startAsyncRead %s stdOutFd PROCESS_PTR->stdout_file: %p fd: %d", + mCmdLine, PROCESS_PTR->stdout_file, stdOutFd ); } + if ( stdErrFd && stdOutFd != stdErrFd ) { pollfds.emplace_back(); - pollfds.back().fd = - fcntl( stdErrFd, F_SETFL, fcntl( stdErrFd, F_GETFL ) | O_NONBLOCK ) == 0 ? stdErrFd - : -1; + int currentFlags = fcntl( stdErrFd, F_GETFL ); + if ( currentFlags == -1 ) { + pollfds.back().fd = -1; // Invalid FD + Log::error( "Process::startAsyncRead %s Failed to get flags for stdout fd", + mCmdLine ); + } else { + // Set non-blocking + if ( fcntl( stdErrFd, F_SETFL, currentFlags | O_NONBLOCK ) == 0 ) { + pollfds.back().fd = stdErrFd; + } else { + pollfds.back().fd = -1; + Log::error( "Process::startAsyncRead %s Failed to set O_NONBLOCK on stdout", + mCmdLine ); + } + } pollfds.back().events = POLLIN; + } else if ( !stdErrFd ) { + Log::error( "Process::startAsyncRead %s stdOutFd PROCESS_PTR->stderr_file: %p fd: %d", + PROCESS_PTR->stderr_file, stdErrFd ); } std::string buffer; buffer.resize( mBufferSize ); bool anyOpen = !pollfds.empty(); + if ( !anyOpen ) { + Log::error( "Process::startAsyncRead no fds open, aborting for command: %s", mCmdLine ); + } else { + Log::info( "Process::startAsyncRead fds open, starting polling command: %s", mCmdLine ); + } + while ( anyOpen && !mShuttingDown ) { int res = poll( pollfds.data(), static_cast( pollfds.size() ), 100 ); if ( res > 0 ) { @@ -477,6 +520,10 @@ void Process::startAsyncRead( ReadFn readStdOut, ReadFn readStdErr ) { mReadStdErrFn( buffer.c_str(), static_cast( n ) ); } else if ( n == 0 || ( n < 0 && errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK ) ) { + Log::info( + "Process::startAsyncRead %s read failed for fd: %d, read " + "result was %d, errno is %d", + mCmdLine, pollfds[i].fd, n, errno ); pollfds[i].fd = -1; continue; } @@ -494,15 +541,22 @@ void Process::startAsyncRead( ReadFn readStdOut, ReadFn readStdErr ) { mReadStdErrFn( buffer.c_str(), static_cast( n ) ); } } + Log::info( "Process::startAsyncRead %s polling POLLHUP for fd: %d", + mCmdLine, pollfds[i].fd ); pollfds[i].fd = -1; continue; } anyOpen = true; } } - } else if ( res < 0 && errno != EINTR ) + } else if ( res < 0 && errno != EINTR ) { + Log::error( "Process::startAsyncRead polling interrupted for: %s", mCmdLine ); break; + } } + + Log::info( "Process::startAsyncRead polling ended for: %s, any open: %s, shutting down: %s", + mCmdLine, anyOpen ? "true" : "false", mShuttingDown ? "true" : "false" ); } ); #endif } diff --git a/src/eepp/window/backend/SDL2/clipboardsdl2.cpp b/src/eepp/window/backend/SDL2/clipboardsdl2.cpp index 8ec43cd52..130ba8847 100644 --- a/src/eepp/window/backend/SDL2/clipboardsdl2.cpp +++ b/src/eepp/window/backend/SDL2/clipboardsdl2.cpp @@ -49,12 +49,12 @@ std::string ClipboardSDL::getText() { #endif } -std::string ClipboardSDL::getPrimarySelectionText() { -#if EE_PLATFORM == EE_PLATFORM_EMSCRIPTEN - return ""; -#else +bool ClipboardSDL::hasPrimarySelection() const { + return SDL_HasPrimarySelectionText(); +} -#if SDL_VERSION_ATLEAST(2, 26, 0) +std::string ClipboardSDL::getPrimarySelectionText() { +#if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN && SDL_VERSION_ATLEAST( 2, 26, 0 ) if ( SDL_HasPrimarySelectionText() ) { char* text = SDL_GetPrimarySelectionText(); std::string str( text ); @@ -63,13 +63,14 @@ std::string ClipboardSDL::getPrimarySelectionText() { } #endif - return ""; -#endif + return getText(); } void ClipboardSDL::setPrimarySelectionText( const std::string& text ) { -#if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN && SDL_VERSION_ATLEAST(2, 26, 0) - SDL_SetPrimarySelectionText( text.c_str() ); +#if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN && SDL_VERSION_ATLEAST( 2, 26, 0 ) + if ( SDL_HasPrimarySelectionText() ) { + SDL_SetPrimarySelectionText( text.c_str() ); + } #endif } diff --git a/src/eepp/window/backend/SDL2/clipboardsdl2.hpp b/src/eepp/window/backend/SDL2/clipboardsdl2.hpp index 6832454ed..d6f4e446d 100644 --- a/src/eepp/window/backend/SDL2/clipboardsdl2.hpp +++ b/src/eepp/window/backend/SDL2/clipboardsdl2.hpp @@ -21,6 +21,8 @@ class EE_API ClipboardSDL : public Clipboard { void setText( const std::string& text ); + bool hasPrimarySelection() const; + std::string getPrimarySelectionText(); void setPrimarySelectionText( const std::string& text ); diff --git a/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp b/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp index a63e02e93..e15fb4e40 100644 --- a/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp +++ b/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp @@ -947,9 +947,8 @@ void TerminalDisplay::onMouseUp( const Vector2i& pos, const Uint32& flags ) { mDraggingSel = false; } - if ( flags & EE_BUTTON_LMASK ) { - auto selection = mTerminal->getSelection(); - mWindow->getClipboard()->setPrimarySelectionText( selection ); + if ( ( flags & EE_BUTTON_LMASK ) && mWindow->getClipboard()->hasPrimarySelection() ) { + mWindow->getClipboard()->setPrimarySelectionText( mTerminal->getSelection() ); } Uint32 smod = sanitizeMod( mWindow->getInput()->getModState() ); diff --git a/src/thirdparty/subprocess/subprocess.h b/src/thirdparty/subprocess/subprocess.h index a306b0211..7818a9b97 100644 --- a/src/thirdparty/subprocess/subprocess.h +++ b/src/thirdparty/subprocess/subprocess.h @@ -183,7 +183,7 @@ subprocess_weak int subprocess_terminate(struct subprocess_s *const process); /// /// The only safe way to read from the standard output of a process during it's /// execution is to use the `subprocess_option_enable_async` option in -/// conjuction with this method. +/// conjunction with this method. subprocess_weak unsigned subprocess_read_stdout(struct subprocess_s *const process, char *const buffer, unsigned size); @@ -197,7 +197,7 @@ subprocess_read_stdout(struct subprocess_s *const process, char *const buffer, /// /// The only safe way to read from the standard error of a process during it's /// execution is to use the `subprocess_option_enable_async` option in -/// conjuction with this method. +/// conjunction with this method. subprocess_weak unsigned subprocess_read_stderr(struct subprocess_s *const process, char *const buffer, unsigned size); @@ -234,6 +234,7 @@ subprocess_weak void subprocess_init_shutdown(struct subprocess_s *const process #include #include #include +#include #endif #if defined(_WIN32) @@ -1509,28 +1510,33 @@ subprocess_write_stdin(struct subprocess_s *const process, char *const buffer, } return SUBPROCESS_CAST(unsigned, bytes_write); #else - const int fd = fileno(process->stdin_file); - int bytes_to_write = size; - char* buffer_to_write = buffer; - do { - const ssize_t ret = write(fd, buffer_to_write, bytes_to_write); + const int fd = fileno(process->stdin_file); + int bytes_to_write = size; + char* buffer_to_write = buffer; + do { + const ssize_t ret = write(fd, buffer_to_write, bytes_to_write); - if (ret > 0) { - bytes_to_write -= ret; - buffer_to_write += ret; - fsync(fd); - } else if (ret <= 0) { - if (ret == -1) { - if (((errno == EAGAIN ) || (errno == EINPROGRESS)) && !process->shutting_down) { - continue; - } - return -1; - } - if (ret == 0) - return 0; - } - } while ( bytes_to_write ); - return bytes_to_write == 0 ? size : -1; + if (ret > 0) { + bytes_to_write -= ret; + buffer_to_write += ret; + fsync(fd); + } else if (ret <= 0) { + if (ret == -1) { + if (((errno == EAGAIN ) || (errno == EINPROGRESS)) && !process->shutting_down) { + struct pollfd pfd; + pfd.fd = fd; + pfd.events = POLLOUT; + // Wait up to 1ms, then check shutting_down again + poll(&pfd, 1, 1); + continue; + } + return -1; + } + if (ret == 0) + return 0; + } + } while ( bytes_to_write ); + return bytes_to_write == 0 ? size : -1; #endif } diff --git a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp index 9b656ed00..0a2631cd7 100644 --- a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp +++ b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp @@ -129,7 +129,7 @@ class AutoCompletePlugin : public Plugin { bool mDirty{ false }; bool mReplacing{ false }; bool mSignatureHelpVisible{ false }; - bool mHighlightSuggestions{ false }; + bool mHighlightSuggestions{ true }; struct DocCache { Uint64 changeId{ static_cast( -1 ) }; SymbolsList symbols; diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp index f89b2ee83..c99a7eaa0 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -467,12 +467,8 @@ PluginRequestHandle LSPClientPlugin::processTextDocumentSymbol( const PluginMess auto handler = [uri, this]( const PluginIDType& id, LSPSymbolInformationList&& res ) { setDocumentSymbolsFromResponse( id, uri, std::move( res ) ); }; - if ( Engine::instance()->isMainThread() ) { - server->getThreadPool()->run( - [server, uri, handler]() { server->documentSymbols( uri, handler ); } ); - } else { - server->documentSymbols( uri, handler ); - } + + server->documentSymbols( uri, handler ); return { uri.toString() }; } diff --git a/src/tools/ecode/plugins/lsp/lspclientserver.cpp b/src/tools/ecode/plugins/lsp/lspclientserver.cpp index 58eb718a9..bf0a5cf9f 100644 --- a/src/tools/ecode/plugins/lsp/lspclientserver.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientserver.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -1262,7 +1263,7 @@ void LSPClientServer::initialize() { // Send configuration immediately after initialized didChangeConfiguration( mLSP.settings, mWorkspaceFolder.getFSPath(), true ); - sendQueuedMessages(); + sendQueuedMessagesAsync(); notifyServerInitialized(); // Broadcast the language capabilities to all the interested plugins @@ -1395,19 +1396,27 @@ bool LSPClientServer::start() { } bool LSPClientServer::registerDoc( const std::shared_ptr& doc ) { - Lock l( mClientsMutex ); - for ( TextDocument* cdoc : mDocs ) { - if ( cdoc == doc.get() ) { - if ( mClients.find( doc.get() ) == mClients.end() ) { - mClients[doc.get()] = std::make_unique( this, doc.get() ); - return true; + { + Lock l( mClientsMutex ); + for ( TextDocument* cdoc : mDocs ) { + if ( cdoc == doc.get() ) { + if ( mClients.find( doc.get() ) == mClients.end() ) { + mClients[doc.get()] = std::make_unique( this, doc.get() ); + return true; + } + return false; } - return false; } } - mClients[doc.get()] = std::make_unique( this, doc.get() ); - mDocs.emplace_back( doc.get() ); + auto client = std::make_unique( this, doc.get() ); + + { + Lock l( mClientsMutex ); + mClients[doc.get()] = std::move( client ); + mDocs.emplace_back( doc.get() ); + } + doc->registerClient( mClients[doc.get()].get() ); return true; } @@ -1536,6 +1545,7 @@ LSPClientServer::LSPRequestHandle LSPClientServer::write( json&& msg, const Json mProcess.write( sjson ); } } else { + Lock l( mQueuedMessagesMutex ); mQueuedMessages.push_back( { std::move( msg ), h, eh } ); } } catch ( const json::exception& e ) { @@ -1546,6 +1556,19 @@ LSPClientServer::LSPRequestHandle LSPClientServer::write( json&& msg, const Json return ret; } +void LSPClientServer::writeAsync( json&& msg, const JsonReplyHandler& h, const JsonReplyHandler& eh, + const int id ) { + if ( mShuttingDown || !isRunning() ) + return; + getThreadPool()->run( [this, msg = std::move( msg ), h, eh, id]() mutable { + if ( mShuttingDown || !isRunning() ) + return; + mWritingStdIn++; + write( std::move( msg ), h, eh, id ); + mWritingStdIn--; + } ); +} + void LSPClientServer::sendAsync( json&& msg, const JsonReplyHandler& h, const JsonReplyHandler& eh ) { if ( mShuttingDown ) @@ -1759,25 +1782,22 @@ const std::shared_ptr& LSPClientServer::getThreadPool() const { return mManager->getThreadPool(); } -LSPClientServer::LSPRequestHandle LSPClientServer::documentSymbols( const URI& document, - const JsonReplyHandler& h, - const JsonReplyHandler& eh ) { - auto params = textDocumentParams( document ); - return send( newRequest( "textDocument/documentSymbol", params ), h, eh ); -} - -LSPClientServer::LSPRequestHandle -LSPClientServer::documentFoldingRange( const URI& document, const JsonReplyHandler& h, +void LSPClientServer::documentSymbols( const URI& document, const JsonReplyHandler& h, const JsonReplyHandler& eh ) { auto params = textDocumentParams( document ); - return send( newRequest( "textDocument/foldingRange", params ), h, eh ); + sendAsync( newRequest( "textDocument/documentSymbol", params ), h, eh ); } -LSPClientServer::LSPRequestHandle -LSPClientServer::documentFoldingRange( const URI& document, - const ReplyHandler>& h, - const ReplyHandler& eh ) { - return documentFoldingRange( +void LSPClientServer::documentFoldingRange( const URI& document, const JsonReplyHandler& h, + const JsonReplyHandler& eh ) { + auto params = textDocumentParams( document ); + sendAsync( newRequest( "textDocument/foldingRange", params ), h, eh ); +} + +void LSPClientServer::documentFoldingRange( const URI& document, + const ReplyHandler>& h, + const ReplyHandler& eh ) { + documentFoldingRange( document, [h]( const IdType& id, const json& json ) { if ( h ) @@ -1789,11 +1809,10 @@ LSPClientServer::documentFoldingRange( const URI& document, } ); } -LSPClientServer::LSPRequestHandle -LSPClientServer::documentSymbols( const URI& document, - const WReplyHandler& h, - const ReplyHandler& eh ) { - return documentSymbols( +void LSPClientServer::documentSymbols( const URI& document, + const WReplyHandler& h, + const ReplyHandler& eh ) { + documentSymbols( document, [this, h]( const IdType& id, const json& json ) { if ( h ) @@ -1805,9 +1824,9 @@ LSPClientServer::documentSymbols( const URI& document, } ); } -LSPClientServer::LSPRequestHandle LSPClientServer::documentSymbolsBroadcast( const URI& document ) { - return documentSymbols( document, [this, document]( const PluginIDType& id, - LSPSymbolInformationList&& res ) { +void LSPClientServer::documentSymbolsBroadcast( const URI& document ) { + documentSymbols( document, [this, document]( const PluginIDType& id, + LSPSymbolInformationList&& res ) { getManager()->getPlugin()->setDocumentSymbolsFromResponse( id, document, std::move( res ) ); } ); } @@ -1991,25 +2010,25 @@ void LSPClientServer::processRequest( const json& msg ) { } ); return; } else if ( method == "window/workDoneProgress/create" ) { - write( newEmptyResult( msgid ) ); + writeAsync( newEmptyResult( msgid ) ); return; } else if ( method == "workspace/semanticTokens/refresh" ) { refreshSmenaticHighlighting(); - write( newEmptyResult( msgid ) ); + writeAsync( newEmptyResult( msgid ) ); return; } else if ( method == "workspace/codeLens/refresh" ) { refreshCodeLens(); - write( newEmptyResult( msgid ) ); + writeAsync( newEmptyResult( msgid ) ); return; } else if ( method == "client/registerCapability" ) { registerCapabilities( msg[MEMBER_PARAMS] ); - write( newEmptyResult( msgid ) ); + writeAsync( newEmptyResult( msgid ) ); return; } else if ( method == "window/showMessageRequest" ) { auto msgReq = parseMessageRequest( msg[MEMBER_PARAMS] ); mManager->getPluginManager()->sendBroadcast( PluginMessageType::ShowMessage, PluginMessageFormat::ShowMessage, &msgReq ); - write( newEmptyResult( msgid ) ); + writeAsync( newEmptyResult( msgid ) ); return; } else if ( method == "window/showDocument" ) { auto showDoc = parseShowDocument( msg[MEMBER_PARAMS] ); @@ -2022,7 +2041,7 @@ void LSPClientServer::processRequest( const json& msg ) { mManager->getPluginManager()->sendBroadcast( PluginMessageType::ShowDocument, PluginMessageFormat::ShowDocument, &showDoc ); } - write( newSuccessResult( msgid ) ); + writeAsync( newSuccessResult( msgid ) ); return; } else if ( method == "workspace/configuration" ) { json results = json::array(); @@ -2099,10 +2118,10 @@ void LSPClientServer::processRequest( const json& msg ) { } json response = newID( msgid ); response[MEMBER_RESULT] = results; - write( std::move( response ) ); + writeAsync( std::move( response ) ); return; } - write( newError( LSPErrorCode::MethodNotFound, method ), nullptr, nullptr, msgid ); + writeAsync( newError( LSPErrorCode::MethodNotFound, method ), nullptr, nullptr, msgid ); } void LSPClientServer::readStdOut( const char* bytes, size_t n ) { @@ -2256,16 +2275,27 @@ void LSPClientServer::readStdErr( const char* bytes, size_t n ) { mReceiveErr = received; if ( !received.empty() ) - Log::debug( "LSPClientServer::readStdErr server %s:\n%s", mLSP.name, received ); + Log::info( "LSPClientServer::readStdErr server %s:\n%s", mLSP.name, received ); if ( !isRunning() ) notifyServerError(); } -void LSPClientServer::sendQueuedMessages() { - for ( auto& msg : mQueuedMessages ) - write( std::move( msg.msg ), msg.h, msg.eh ); - mQueuedMessages.clear(); +void LSPClientServer::sendQueuedMessagesAsync() { + if ( mShuttingDown ) + return; + getThreadPool()->run( [this]() mutable { + if ( mShuttingDown ) + return; + for ( auto& msg : mQueuedMessages ) { + if ( mShuttingDown ) + return; + mWritingStdIn++; + write( std::move( msg.msg ), msg.h, msg.eh ); + mWritingStdIn--; + } + mQueuedMessages.clear(); + } ); } void LSPClientServer::goToLocation( const json& res ) { @@ -2612,6 +2642,9 @@ void LSPClientServer::shutdown() { mHandlers.clear(); } + while ( mWritingStdIn ) + Sys::sleep( Milliseconds( 1 ) ); + sendSync( newRequest( "shutdown" ), [this]( const IdType&, const json& ) { diff --git a/src/tools/ecode/plugins/lsp/lspclientserver.hpp b/src/tools/ecode/plugins/lsp/lspclientserver.hpp index 16064d1b6..63ab7a573 100644 --- a/src/tools/ecode/plugins/lsp/lspclientserver.hpp +++ b/src/tools/ecode/plugins/lsp/lspclientserver.hpp @@ -97,22 +97,20 @@ class LSPClientServer { const LSPDefinition& getDefinition() const { return mLSP; } - LSPRequestHandle documentSymbols( const URI& document, const JsonReplyHandler& h, - const JsonReplyHandler& eh ); + void documentSymbols( const URI& document, const JsonReplyHandler& h, + const JsonReplyHandler& eh ); - LSPRequestHandle documentSymbols( const URI& document, - const WReplyHandler& h, - const ReplyHandler& eh = {} ); + void documentSymbols( const URI& document, const WReplyHandler& h, + const ReplyHandler& eh = {} ); - LSPClientServer::LSPRequestHandle documentFoldingRange( const URI& document, - const JsonReplyHandler& h, - const JsonReplyHandler& eh ); + void documentFoldingRange( const URI& document, const JsonReplyHandler& h, + const JsonReplyHandler& eh ); - LSPRequestHandle documentFoldingRange( const URI& document, - const ReplyHandler>& h, - const ReplyHandler& eh = {} ); + void documentFoldingRange( const URI& document, + const ReplyHandler>& h, + const ReplyHandler& eh = {} ); - LSPRequestHandle documentSymbolsBroadcast( const URI& document ); + void documentSymbolsBroadcast( const URI& document ); LSPRequestHandle didOpen( const URI& document, const std::string& text, int version ); @@ -291,6 +289,7 @@ class LSPClientServer { bool mNotifiedServerError{ false }; bool mShuttingDown{ false }; bool mIsProcessingQueue{ false }; + std::atomic mWritingStdIn{ 0 }; struct QueueMessage { json msg; JsonReplyHandler h; @@ -310,6 +309,7 @@ class LSPClientServer { }; std::queue mDidChangeQueue; Mutex mDidChangeMutex; + Mutex mQueuedMessagesMutex; std::mutex mShutdownMutex; std::condition_variable mShutdownCond; std::atomic mLastMsgId{ 0 }; @@ -321,9 +321,12 @@ class LSPClientServer { LSPRequestHandle write( json&& msg, const JsonReplyHandler& h = nullptr, const JsonReplyHandler& eh = nullptr, const int id = 0 ); + void writeAsync( json&& msg, const JsonReplyHandler& h = nullptr, + const JsonReplyHandler& eh = nullptr, const int id = 0 ); + void initialize(); - void sendQueuedMessages(); + void sendQueuedMessagesAsync(); void processNotification( const json& msg ); diff --git a/src/tools/ecode/plugins/lsp/lspdocumentclient.cpp b/src/tools/ecode/plugins/lsp/lspdocumentclient.cpp index 3b3dbf3bf..4b3100187 100644 --- a/src/tools/ecode/plugins/lsp/lspdocumentclient.cpp +++ b/src/tools/ecode/plugins/lsp/lspdocumentclient.cpp @@ -411,12 +411,7 @@ void LSPDocumentClient::requestSymbols() { if ( !server->getCapabilities().documentSymbolProvider ) return; URI uri = mDoc->getURI(); - if ( Engine::instance()->isMainThread() ) { - mServer->getThreadPool()->run( - [server, uri]() { server->documentSymbolsBroadcast( uri ); } ); - } else { - server->documentSymbolsBroadcast( uri ); - } + server->documentSymbolsBroadcast( uri ); } void LSPDocumentClient::requestFoldRange() { @@ -439,12 +434,7 @@ void LSPDocumentClient::requestFoldRange() { doc->getFoldRangeService().setFoldingRegions( regions ); }; - if ( Engine::instance()->isMainThread() ) { - server->getThreadPool()->run( - [server, uri, handler]() { server->documentFoldingRange( uri, handler ); } ); - } else { - server->documentFoldingRange( uri, handler ); - } + server->documentFoldingRange( uri, handler ); } void LSPDocumentClient::requestSymbolsDelayed() {