diff --git a/include/eepp/ui/doc/syntaxdefinition.hpp b/include/eepp/ui/doc/syntaxdefinition.hpp index 2da26f47d..a67f7ee35 100644 --- a/include/eepp/ui/doc/syntaxdefinition.hpp +++ b/include/eepp/ui/doc/syntaxdefinition.hpp @@ -74,6 +74,10 @@ class EE_API SyntaxDefinition { const std::string& getLSPName() const; + void setVisible( bool visible ); + + bool isVisible() const; + protected: std::string mLanguageName; String::HashType mLanguageId; @@ -83,6 +87,7 @@ class EE_API SyntaxDefinition { std::string mComment; std::vector mHeaders; std::string mLSPName; + bool mVisible{ true }; }; }}} // namespace EE::UI::Doc diff --git a/src/eepp/ui/doc/syntaxdefinition.cpp b/src/eepp/ui/doc/syntaxdefinition.cpp index cea8dc94c..5d9a3a45c 100644 --- a/src/eepp/ui/doc/syntaxdefinition.cpp +++ b/src/eepp/ui/doc/syntaxdefinition.cpp @@ -115,6 +115,14 @@ const std::string& SyntaxDefinition::getLSPName() const { return mLSPName; } +void SyntaxDefinition::setVisible( bool visible ) { + mVisible = visible; +} + +bool SyntaxDefinition::isVisible() const { + return mVisible; +} + const std::string& SyntaxDefinition::getLanguageName() const { return mLanguageName; } diff --git a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp index ac681dded..f5a712061 100644 --- a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp +++ b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp @@ -153,7 +153,7 @@ void SyntaxDefinitionManager::addXML() { void SyntaxDefinitionManager::addHTML() { add( { "HTML", - { "%.html?$", "%.php$", "%.php3$", "%.php4$", "%.php5$", "%.phtml", "%.handlebars" }, + { "%.html?$", "%.phtml", "%.handlebars" }, { { { "<%s*[sS][cC][rR][iI][pP][tT]%s+[tT][yY][pP][eE]%s*=%s*['\"]%a+/" "[jJ][aA][vV][aA][sS][cC][rR][iI][pP][tT]['\"]%s*>", @@ -166,7 +166,7 @@ void SyntaxDefinitionManager::addHTML() { { { "<%s*[sS][tT][yY][lL][eE][^>]*>", "<%s*/%s*[sS][tT][yY][lL][eE]%s*>" }, "function", "CSS" }, - { { "<%?p?h?p?", "%?>" }, "function", "PHP" }, + { { "<%?p?h?p?", "%?>" }, "function", "PHPCore" }, { { "" }, "comment" }, { { "%f[^>][^<]", "%f[<]" }, "normal" }, { { "\"", "\"", "\\" }, "string" }, @@ -406,7 +406,7 @@ void SyntaxDefinitionManager::addMarkdown() { { { "```[Tt]ype[Ss]cript", "```" }, "function", "TypeScript" }, { { "```[Pp]ython", "```" }, "function", "Python" }, { { "```[Bb]ash", "```" }, "function", "Bash" }, - { { "```[Pp][Hh][Pp]", "```" }, "function", "PHP" }, + { { "```[Pp][Hh][Pp]", "```" }, "function", "PHPCore" }, { { "```[Ss][Qq][Ll]", "```" }, "function", "SQL" }, { { "```[Gg][Ll][Ss][Ll]", "```" }, "function", "GLSL" }, { { "```[Ii][Nn][Ii]", "```" }, "function", "Config File" }, @@ -841,6 +841,38 @@ void SyntaxDefinitionManager::addCPP() { void SyntaxDefinitionManager::addPHP() { add( { "PHP", + { "%.php$", "%.php3$", "%.php4$", "%.php5$" }, + { + { { "<%s*[sS][cC][rR][iI][pP][tT]%s+[tT][yY][pP][eE]%s*=%s*['\"]%a+/" + "[jJ][aA][vV][aA][sS][cC][rR][iI][pP][tT]['\"]%s*>", + "<%s*/[sS][cC][rR][iI][pP][tT]>" }, + "function", + "JavaScript" }, + { { "<%s*[sS][cC][rR][iI][pP][tT]%s*>", "<%s*/%s*[sS][cC][rR][iI][pP][tT]>" }, + "function", + "JavaScript" }, + { { "<%s*[sS][tT][yY][lL][eE][^>]*>", "<%s*/%s*[sS][tT][yY][lL][eE]%s*>" }, + "function", + "CSS" }, + { { "<%?p?h?p?", "%?>" }, "function", "PHPCore" }, + { { "" }, "comment" }, + { { "%f[^>][^<]", "%f[<]" }, "normal" }, + { { "\"", "\"", "\\" }, "string" }, + { { "'", "'", "\\" }, "string" }, + { { "0x[%da-fA-F]+" }, "number" }, + { { "-?%d+[%d%.]*f?" }, "number" }, + { { "-?%.?%d+f?" }, "number" }, + { { "%f[^<]![%a_][%w%_%-]*" }, "keyword2" }, + { { "%f[^<][%a_][%w%_%-]*" }, "function" }, + { { "%f[^<]/[%a_][%w%_%-]*" }, "function" }, + { { "[%a_][%w_]*" }, "keyword" }, + { { "[/<>=]" }, "operator" }, + }, + {}, + "", + { "^#!.*[ /]php" } } ); + + add( { "PHPCore", {}, { { { "<%?p?h?p?" }, "function" }, @@ -900,7 +932,9 @@ void SyntaxDefinitionManager::addPHP() { { "NULL", "literal" }, { "parent", "literal" }, { "self", "literal" }, { "echo", "function" } }, "//", - { "^#!.*[ /]php" } } ); + {}, + "php" } ) + .setVisible( false ); } void SyntaxDefinitionManager::addSQL() { @@ -3774,7 +3808,8 @@ SyntaxDefinition& SyntaxDefinitionManager::getByLanguageNameRef( const std::stri std::vector SyntaxDefinitionManager::getLanguageNames() const { std::vector names; for ( auto& style : mDefinitions ) { - names.push_back( style.getLanguageName() ); + if ( style.isVisible() ) + names.push_back( style.getLanguageName() ); } std::sort( names.begin(), names.end() ); return names; diff --git a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp index dd1607a74..913af639d 100644 --- a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp +++ b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp @@ -21,7 +21,10 @@ namespace ecode { static json getURIJSON( TextDocument* doc, const PluginIDType& id ) { json data; data["uri"] = doc->getURI().toString(); - data["id"] = id; + if ( id.isInteger() ) + data["id"] = id.asInt(); + else + data["id"] = id.asString(); return data; } @@ -55,7 +58,10 @@ fuzzyMatchSymbols( const std::vector& sy } std::sort( matches.begin(), matches.end(), - []( const auto& left, const auto& right ) { return left.score > right.score; } ); + []( const AutoCompletePlugin::Suggestion& left, + const AutoCompletePlugin::Suggestion& right ) { + return left.score > right.score && left.kind != LSPCompletionItemKind::Text; + } ); return matches; } @@ -419,11 +425,13 @@ PluginRequestHandle AutoCompletePlugin::processCodeCompletion( const LSPCompletionList& completion ) { SymbolsList suggestions; for ( const auto& item : completion.items ) { - if ( !item.textEdit.text.empty() ) + if ( !item.insertText.empty() ) + suggestions.push_back( + { item.kind, item.insertText, item.detail, item.sortText, item.textEdit.range } ); + + else if ( !item.textEdit.text.empty() ) suggestions.push_back( { item.kind, item.textEdit.text, item.detail, item.sortText, item.textEdit.range } ); - else if ( !item.insertText.empty() ) - suggestions.push_back( { item.kind, item.insertText, item.detail, item.sortText } ); else suggestions.push_back( { item.kind, item.filterText, item.detail, item.sortText } ); } diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp index 84ae0bec6..d319d1e52 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -116,7 +116,7 @@ PluginRequestHandle LSPClientPlugin::processCancelRequest( const PluginMessage& if ( !server ) return {}; - return server->cancel( msg.asJSON().value( "id", 0 ) ); + return server->cancel( LSPClientServer::getID( msg.asJSON() ) ); } PluginRequestHandle LSPClientPlugin::processMessage( const PluginMessage& msg ) { diff --git a/src/tools/ecode/plugins/lsp/lspclientserver.cpp b/src/tools/ecode/plugins/lsp/lspclientserver.cpp index efe50b8d3..eddbf5d03 100644 --- a/src/tools/ecode/plugins/lsp/lspclientserver.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientserver.cpp @@ -55,10 +55,22 @@ static json newRequest( const std::string& method, const json& params = json{} ) return j; } -static json newResponse( const std::string& method, const int& id ) { +static json newID( const PluginIDType& id ) { + json j; + if ( id.isInteger() ) + j[MEMBER_ID] = id.asInt(); + else + j[MEMBER_ID] = id.asString(); + return j; +} + +static json newResponse( const std::string& method, const PluginIDType& id ) { json j; j[MEMBER_METHOD] = method; - j[MEMBER_ID] = id; + if ( id.isInteger() ) + j[MEMBER_ID] = id.asInt(); + else + j[MEMBER_ID] = id.asString(); return j; } @@ -301,8 +313,8 @@ static std::vector parseDiagnosticsArr( const json& result ) { ? String::toString( diag["code"].get() ) : diag.at( "code" ).get() ) : ""; - auto source = diag.at( "source" ).get(); - auto message = diag.at( MEMBER_MESSAGE ).get(); + auto source = diag.value( "source", "" ); + auto message = diag.value( MEMBER_MESSAGE, "" ); std::vector relatedInfoList; if ( diag.contains( "relatedInformation" ) ) { const auto relatedInfo = diag.at( "relatedInformation" ); @@ -856,14 +868,14 @@ const LSPServerCapabilities& LSPClientServer::getCapabilities() const { return mCapabilities; } -LSPClientServer::LSPRequestHandle LSPClientServer::cancel( int reqid ) { +LSPClientServer::LSPRequestHandle LSPClientServer::cancel( const PluginIDType& reqid ) { size_t res = 0; { Lock l( mHandlersMutex ); res = mHandlers.erase( reqid ) > 0; } if ( res > 0 ) { - auto params = json{ { MEMBER_ID, reqid } }; + auto params = newID( reqid ); return write( newRequest( "$/cancelRequest", params ) ); } return LSPRequestHandle(); @@ -1096,6 +1108,19 @@ static LSPWorkDoneProgressParams parseWorkDone( const json& json ) { return parseProgress( json ); } +PluginIDType LSPClientServer::getID( const json& json ) { + const auto& memberID = json[MEMBER_ID]; + if ( memberID.is_string() ) { + return memberID.get(); + } else if ( memberID.is_number_integer() ) { + return memberID.get(); + } else if ( memberID.is_number_unsigned() ) { + return memberID.get(); + } + eeASSERT( true ); + return {}; +} + static json newError( const LSPErrorCode& code, const std::string& msg ) { return json{ { MEMBER_ERROR, { { MEMBER_CODE, static_cast( code ) }, { MEMBER_MESSAGE, msg } } } }; @@ -1142,7 +1167,7 @@ void LSPClientServer::processRequest( const json& msg ) { Log::debug( "LSPClientServer::processRequest server %s: %s", mLSP.name.c_str(), msg.dump().c_str() ); auto method = msg[MEMBER_METHOD].get(); - auto msgid = msg[MEMBER_ID].get(); + auto msgid = getID( msg ); // auto params = msg[MEMBER_PARAMS]; // bool handled = false; if ( method == "window/workDoneProgress/create" || method == "client/registerCapability" ) { @@ -1158,7 +1183,7 @@ void LSPClientServer::readStdOut( const char* bytes, size_t n ) { std::string& buffer = mReceive; while ( true ) { - auto index = buffer.find_first_of( CONTENT_LENGTH_HEADER ); + auto index = buffer.find( CONTENT_LENGTH_HEADER ); if ( index == std::string::npos ) { if ( buffer.size() > ( 1 << 20 ) ) buffer.clear(); @@ -1166,8 +1191,8 @@ void LSPClientServer::readStdOut( const char* bytes, size_t n ) { } index += strlen( CONTENT_LENGTH_HEADER ); - auto endindex = buffer.find_first_of( "\r\n", index ); - auto msgstart = buffer.find_first_of( "\r\n\r\n", index ); + auto endindex = buffer.find( "\r\n", index ); + auto msgstart = buffer.find( "\r\n\r\n", index ); if ( endindex == std::string::npos || msgstart == std::string::npos ) break; @@ -1207,9 +1232,9 @@ void LSPClientServer::readStdOut( const char* bytes, size_t n ) { #endif auto res = json::parse( payload ); - int msgid = -1; + PluginIDType msgid; if ( res.contains( MEMBER_ID ) ) { - msgid = res[MEMBER_ID].get(); + msgid = getID( res ); } else { processNotification( res ); continue; @@ -1223,17 +1248,26 @@ void LSPClientServer::readStdOut( const char* bytes, size_t n ) { Log::debug( "LSPClientServer::readStdOut server %s said: \n%s", mLSP.name.c_str(), res.dump().c_str() ); - Lock l( mHandlersMutex ); - auto it = mHandlers.find( msgid ); - if ( it != mHandlers.end() ) { - const auto handler = *it; - mHandlers.erase( it ); - auto& h = handler.second.first; - auto& eh = handler.second.second; - if ( res.contains( MEMBER_ERROR ) && eh ) { - eh( msgid, res[MEMBER_ERROR] ); + HandlersMap::iterator it; + HandlersMap::iterator itEnd; + JsonReplyHandler handlerOK; + JsonReplyHandler handlerErr; + { + Lock l( mHandlersMutex ); + it = mHandlers.find( msgid ); + itEnd = mHandlers.end(); + if ( it != itEnd ) { + handlerOK = it->second.first; + handlerErr = it->second.second; + mHandlers.erase( it ); + } + } + + if ( it != itEnd ) { + if ( res.contains( MEMBER_ERROR ) && handlerErr ) { + handlerErr( msgid, res[MEMBER_ERROR] ); } else { - h( msgid, res[MEMBER_RESULT] ); + handlerOK( msgid, res[MEMBER_RESULT] ); } } else { Log::debug( "LSPClientServer::readStdOut server %s unexpected reply id: %d", diff --git a/src/tools/ecode/plugins/lsp/lspclientserver.hpp b/src/tools/ecode/plugins/lsp/lspclientserver.hpp index a7a352681..fa46d5cb0 100644 --- a/src/tools/ecode/plugins/lsp/lspclientserver.hpp +++ b/src/tools/ecode/plugins/lsp/lspclientserver.hpp @@ -27,6 +27,8 @@ class LSPClientServerManager; class LSPClientServer { public: + static PluginIDType getID( const json& json ); + using IdType = PluginIDType; template using ReplyHandler = std::function; @@ -41,7 +43,7 @@ class LSPClientServer { class LSPRequestHandle : public PluginRequestHandle { public: void cancel() { - if ( server && mId != 0 ) + if ( server && mId.isValid() ) server->cancel( mId ); } @@ -65,7 +67,7 @@ class LSPClientServer { const std::shared_ptr& getThreadPool() const; - LSPRequestHandle cancel( int id ); + LSPRequestHandle cancel( const PluginIDType& id ); LSPRequestHandle send( const json& msg, const JsonReplyHandler& h = nullptr, const JsonReplyHandler& eh = nullptr ); @@ -182,7 +184,8 @@ class LSPClientServer { Process mProcess; std::vector mDocs; std::map> mClients; - std::map> mHandlers; + using HandlersMap = std::map>; + HandlersMap mHandlers; Mutex mClientsMutex; Mutex mHandlersMutex; bool mReady{ false }; @@ -204,7 +207,7 @@ class LSPClientServer { std::queue mDidChangeQueue; Mutex mDidChangeMutex; - int mLastMsgId{ -1 }; + int mLastMsgId{ 0 }; void readStdOut( const char* bytes, size_t n ); diff --git a/src/tools/ecode/plugins/lsp/lspdocumentclient.hpp b/src/tools/ecode/plugins/lsp/lspdocumentclient.hpp index be633b217..28e7c11d5 100644 --- a/src/tools/ecode/plugins/lsp/lspdocumentclient.hpp +++ b/src/tools/ecode/plugins/lsp/lspdocumentclient.hpp @@ -1,7 +1,6 @@ #ifndef ECODE_LSPDOCUMENTCLIENT_HPP #define ECODE_LSPDOCUMENTCLIENT_HPP -#include "../pluginmanager.hpp" #include #include @@ -41,7 +40,7 @@ class LSPDocumentClient : public TextDocument::Client { protected: LSPClientServer* mServer{ nullptr }; TextDocument* mDoc{ nullptr }; - PluginIDType mVersion{ 0 }; + int mVersion{ 0 }; }; } // namespace ecode diff --git a/src/tools/ecode/plugins/pluginmanager.hpp b/src/tools/ecode/plugins/pluginmanager.hpp index 8f4b2f423..867da1e75 100644 --- a/src/tools/ecode/plugins/pluginmanager.hpp +++ b/src/tools/ecode/plugins/pluginmanager.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -76,7 +77,44 @@ enum class PluginMessageFormat { SignatureHelp }; -using PluginIDType = Int64; +class PluginIDType { + public: + enum class Type { Integer, String, Invalid }; + + PluginIDType() {} + + PluginIDType( Int64 val ) : mType( Type::Integer ), mInt( val ) {} + + PluginIDType( const std::string& val ) : mType( Type::String ), mString( val ) {} + + bool operator==( const PluginIDType& right ) { + return mType == right.mType && ( ( mType == Type::Integer && mInt == right.mInt ) || + ( mType == Type::String && mString == right.mString ) ); + } + + bool operator!=( const PluginIDType& right ) { return !( *this == right ); } + + bool is( const Type& type ) const { return type == mType; } + + bool isString() const { return Type::String == mType; } + + bool isInteger() const { return Type::Integer == mType; } + + bool isValid() const { return mType != Type::Invalid; } + + operator Int64() const { return mInt; } + + operator std::string() { return mString; } + + const Int64& asInt() const { return mInt; } + + const std::string& asString() const { return mString; } + + protected: + Type mType{ Type::Invalid }; + Int64 mInt{ std::numeric_limits::max() }; + std::string mString; +}; class LSPClientPlugin;