diff --git a/include/eepp/core/string.hpp b/include/eepp/core/string.hpp index 40c313807..4d49a4b03 100644 --- a/include/eepp/core/string.hpp +++ b/include/eepp/core/string.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -146,6 +147,15 @@ class EE_API String { const std::string& quote = "\"", const bool& removeQuotes = false ); + /** Split a string and hold it on a vector. This function is meant to be used for code + * splitting, detects functions, arrays, braces and quotes for the splitting. + * It does not heap allocate. */ + static void splitCb( std::function + fnCb /* returns true to continue, false to stop iterating */, + const std::string& str, const std::string& delims, + const std::string& delimsPreserve = "", const std::string& quote = "\"", + const bool& removeQuotes = false ); + /** Joins a string vector into a single string */ static std::string join( const std::vector& strArray, const Int8& joinchar = ' ', const bool& appendLastJoinChar = false ); diff --git a/src/eepp/core/string.cpp b/src/eepp/core/string.cpp index 8ed3bc1a1..ea897dba1 100644 --- a/src/eepp/core/string.cpp +++ b/src/eepp/core/string.cpp @@ -838,6 +838,66 @@ std::vector String::split( const std::string& str, const std::strin return tokens; } +void String::splitCb( std::function fnCb, const std::string& str, + const std::string& delims, const std::string& delimsPreserve, + const std::string& quote, const bool& removeQuotes ) { + if ( str.empty() || ( delims.empty() && delimsPreserve.empty() ) ) + return; + + std::string allDelims = delims + delimsPreserve + quote; + + std::string::size_type tokenStart = 0; + std::string::size_type tokenEnd = str.find_first_of( allDelims, tokenStart ); + std::string::size_type tokenLen = 0; + std::string_view token; + while ( true ) { + bool fromQuote = false; + while ( tokenEnd != std::string::npos && + quote.find_first_of( str[tokenEnd] ) != std::string::npos ) { + if ( str[tokenEnd] == '(' ) { + tokenEnd = findCloseBracket( str, tokenEnd, '(', ')' ); + } else if ( str[tokenEnd] == '[' ) { + tokenEnd = findCloseBracket( str, tokenEnd, '[', ']' ); + } else if ( str[tokenEnd] == '{' ) { + tokenEnd = findCloseBracket( str, tokenEnd, '{', '}' ); + } else { + fromQuote = true; + tokenEnd = str.find_first_of( str[tokenEnd], tokenEnd + 1 ); + } + if ( tokenEnd != std::string::npos ) { + tokenEnd = str.find_first_of( allDelims, tokenEnd + 1 ); + } + } + + if ( tokenEnd == std::string::npos ) { + tokenLen = std::string::npos; + } else { + tokenLen = tokenEnd - tokenStart; + } + + token = std::string_view{ str }.substr( tokenStart, tokenLen ); + if ( !token.empty() ) { + if ( fromQuote && removeQuotes && token.size() > 2 ) + token = token.substr( 1, token.size() - 2 ); + if ( !fnCb( token ) ) + return; + } + if ( tokenEnd != std::string::npos && !delimsPreserve.empty() && + delimsPreserve.find_first_of( str[tokenEnd] ) != std::string::npos ) { + if ( !fnCb( std::string_view{ str }.substr( tokenEnd, 1 ) ) ) + return; + } + + tokenStart = tokenEnd; + if ( tokenStart == std::string::npos ) + break; + tokenStart++; + if ( tokenStart == str.length() ) + break; + tokenEnd = str.find_first_of( allDelims, tokenStart ); + } +} + std::string String::join( const std::vector& strArray, const Int8& joinchar, const bool& appendLastJoinChar ) { size_t s = strArray.size(); @@ -1452,7 +1512,7 @@ String String::fromUtf8( const std::string_view& utf8String ) { return String( utf32 ); } -#define iscont( p ) ( ( *(p)&0xC0 ) == 0x80 ) +#define iscont( p ) ( ( *( p ) & 0xC0 ) == 0x80 ) static inline const char* utf8_next( const char* s, const char* e ) { while ( s < e && iscont( s + 1 ) ) @@ -1965,7 +2025,7 @@ bool String::isWholeWord( const String& haystack, const String& needle, const In } size_t String::toUtf32( std::string_view utf8str, String::StringBaseType* buffer, - size_t bufferSize ) { + size_t bufferSize ) { auto start = utf8str.data(); auto end = start + utf8str.size(); size_t pos = 0; diff --git a/src/eepp/ui/css/transitiondefinition.cpp b/src/eepp/ui/css/transitiondefinition.cpp index 2cf4b5dd1..ff572b66b 100644 --- a/src/eepp/ui/css/transitiondefinition.cpp +++ b/src/eepp/ui/css/transitiondefinition.cpp @@ -22,49 +22,52 @@ UnorderedMap TransitionDefinition::parseTrans const PropertyDefinition* propDef = prop->getPropertyDefinition(); if ( propDef->getPropertyId() == PropertyId::Transition ) { - auto strTransitions = String::split( prop->getValue(), ",", ",", "()" ); + String::splitCb( + [&transitions, prop]( std::string_view str ) { + auto strTransition = String::trim( str ); + auto splitTransition = + String::split( std::string{ strTransition }, " ", "", "()" ); - for ( auto tit = strTransitions.begin(); tit != strTransitions.end(); ++tit ) { - auto strTransition = String::trim( *tit ); - auto splitTransition = String::split( strTransition, " ", "", "()" ); + if ( !splitTransition.empty() ) { + TransitionDefinition transitionDef; - if ( !splitTransition.empty() ) { - TransitionDefinition transitionDef; + if ( splitTransition.size() >= 2 ) { + std::string property = String::trim( splitTransition[0] ); + String::toLowerInPlace( property ); - if ( splitTransition.size() >= 2 ) { - std::string property = String::trim( splitTransition[0] ); - String::toLowerInPlace( property ); + Time duration = + StyleSheetProperty( prop->getName(), + String::toLower( splitTransition[1] ) ) + .asTime(); - Time duration = StyleSheetProperty( prop->getName(), - String::toLower( splitTransition[1] ) ) + transitionDef.property = property; + transitionDef.duration = duration; + + if ( splitTransition.size() >= 3 ) { + TimingFunction tf( TimingFunction::parse( splitTransition[2] ) ); + transitionDef.timingFunction = std::move( tf.interpolation ); + transitionDef.timingFunctionParameters = std::move( tf.parameters ); + + if ( transitionDef.timingFunction == Ease::None && + splitTransition.size() == 3 ) { + transitionDef.delay = + StyleSheetProperty( prop->getName(), + String::toLower( splitTransition[2] ) ) .asTime(); - - transitionDef.property = property; - transitionDef.duration = duration; - - if ( splitTransition.size() >= 3 ) { - TimingFunction tf( TimingFunction::parse( splitTransition[2] ) ); - transitionDef.timingFunction = std::move( tf.interpolation ); - transitionDef.timingFunctionParameters = std::move( tf.parameters ); - - if ( transitionDef.timingFunction == Ease::None && - splitTransition.size() == 3 ) { - transitionDef.delay = - StyleSheetProperty( prop->getName(), - String::toLower( splitTransition[2] ) ) - .asTime(); - } else if ( splitTransition.size() >= 4 ) { - transitionDef.delay = - StyleSheetProperty( prop->getName(), - String::toLower( splitTransition[3] ) ) - .asTime(); + } else if ( splitTransition.size() >= 4 ) { + transitionDef.delay = + StyleSheetProperty( prop->getName(), + String::toLower( splitTransition[3] ) ) + .asTime(); + } } - } - transitions[transitionDef.getProperty()] = transitionDef; + transitions[transitionDef.getProperty()] = transitionDef; + } } - } - } + return true; + }, + prop->getValue(), ",", ",", "()" ); } else if ( propDef->getPropertyId() == PropertyId::TransitionDuration ) { auto strDurations = String::split( prop->getValue(), ',' ); diff --git a/src/eepp/ui/uitreeview.cpp b/src/eepp/ui/uitreeview.cpp index c238d4ddc..77405c2e9 100644 --- a/src/eepp/ui/uitreeview.cpp +++ b/src/eepp/ui/uitreeview.cpp @@ -383,6 +383,13 @@ void UITreeView::drawChilds() { mVScroll->nodeDraw(); } +struct OverFindTraverseTreeVars { + UITreeView* tree; + int realIndex; + Vector2f point; + Float rowHeight; +}; + Node* UITreeView::overFind( const Vector2f& point ) { ScopedOp op( [this] { mUISceneNode->setIsLoading( true ); }, [this] { mUISceneNode->setIsLoading( false ); } ); @@ -400,18 +407,19 @@ Node* UITreeView::overFind( const Vector2f& point ) { return pOver; int realIndex = 0; Float rowHeight = getRowHeight(); - traverseTree( [this, &pOver, &realIndex, point, rowHeight]( - int, const ModelIndex& index, const size_t&, const Float& yOffset ) { - if ( yOffset - mScrollOffset.y > mSize.getHeight() ) - return IterationDecision::Stop; - if ( yOffset - mScrollOffset.y + rowHeight < 0 ) + OverFindTraverseTreeVars v{ this, realIndex, point, rowHeight }; + traverseTree( + [&v, &pOver]( int, const ModelIndex& index, const size_t&, const Float& yOffset ) { + if ( yOffset - v.tree->mScrollOffset.y > v.tree->mSize.getHeight() ) + return IterationDecision::Stop; + if ( yOffset - v.tree->mScrollOffset.y + v.rowHeight < 0 ) + return IterationDecision::Continue; + pOver = v.tree->updateRow( v.realIndex, index, yOffset )->overFind( v.point ); + v.realIndex++; + if ( pOver ) + return IterationDecision::Stop; return IterationDecision::Continue; - pOver = updateRow( realIndex, index, yOffset )->overFind( point ); - realIndex++; - if ( pOver ) - return IterationDecision::Stop; - return IterationDecision::Continue; - } ); + } ); if ( !pOver ) pOver = this; } diff --git a/src/thirdparty/efsw b/src/thirdparty/efsw index 62f785c56..87abe5999 160000 --- a/src/thirdparty/efsw +++ b/src/thirdparty/efsw @@ -1 +1 @@ -Subproject commit 62f785c56b7a34f035193d4cb831921347b586b8 +Subproject commit 87abe599995d5646f5d83cf2e3a225bd73148b3a diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp index 0c8eeeff4..fd7525c00 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -31,6 +31,11 @@ namespace ecode { #define LSPCLIENT_THREADED 0 #endif +static Action::UniqueID getMouseMoveHash( UICodeEditor* editor ) { + return hashCombine( String::hash( "LSPClientPlugin::onMouseMove-" ), + reinterpret_cast( editor ) ); +} + static json getURIAndPositionJSON( UICodeEditor* editor ) { json data; auto doc = editor->getDocumentRef(); @@ -256,25 +261,22 @@ LSPClientPlugin::~LSPClientPlugin() { { Lock l( mDocMutex ); for ( const auto& editor : mEditors ) { + UICodeEditor* codeEditor = editor.first; for ( auto& kb : mKeyBindings ) { - editor.first->getKeyBindings().removeCommandKeybind( kb.first ); - if ( editor.first->hasDocument() ) - editor.first->getDocument().removeCommand( kb.first ); + codeEditor->getKeyBindings().removeCommandKeybind( kb.first ); + if ( codeEditor->hasDocument() ) + codeEditor->getDocument().removeCommand( kb.first ); } for ( auto listener : editor.second ) - editor.first->removeEventListener( listener ); + codeEditor->removeEventListener( listener ); if ( mBreadcrumb ) - editor.first->unregisterTopSpace( this ); - editor.first->unregisterPlugin( this ); + codeEditor->unregisterTopSpace( this ); + codeEditor->unregisterPlugin( this ); + if ( mManager->getSplitter()->editorExists( codeEditor ) ) + codeEditor->removeActionsByTag( getMouseMoveHash( codeEditor ) ); } if ( nullptr == mManager->getSplitter() ) return; - for ( const auto& editor : mEditorsTags ) { - if ( mManager->getSplitter()->editorExists( editor.first ) ) { - for ( const auto& tag : editor.second ) - editor.first->removeActionsByTag( tag ); - } - } } } @@ -1511,7 +1513,6 @@ void LSPClientPlugin::onRegister( UICodeEditor* editor ) { } mEditors.insert( { editor, listeners } ); - mEditorsTags.insert( { editor, UnorderedSet{} } ); mEditorDocs[editor] = editor->getDocumentRef().get(); if ( mReady && editor->hasDocument() && editor->getDocument().hasFilepath() ) @@ -1603,7 +1604,6 @@ void LSPClientPlugin::onUnregister( UICodeEditor* editor ) { editor->unregisterTopSpace( this ); mEditors.erase( editor ); - mEditorsTags.erase( editor ); mEditorDocs.erase( editor ); for ( const auto& ieditor : mEditorDocs ) { if ( ieditor.second == doc ) @@ -1817,12 +1817,8 @@ bool LSPClientPlugin::onMouseMove( UICodeEditor* editor, const Vector2i& positio return false; } - String::HashType tag = hashCombine( String::hash( "LSPClientPlugin::onMouseMove-" ), - String::hash( editor->getDocument().getFilePath() ) ); - mEditorsTags[editor].insert( tag ); editor->debounce( - [this, editor, position, tag]() { - mEditorsTags[editor].erase( tag ); + [this, editor]() { if ( !editorExists( editor ) ) return; auto server = mClientManager.getOneLSPClientServer( editor ); @@ -1830,22 +1826,20 @@ bool LSPClientPlugin::onMouseMove( UICodeEditor* editor, const Vector2i& positio return; server->documentHover( editor->getDocument().getURI(), currentMouseTextPosition( editor ), - [this, editor, position]( const Int64&, const LSPHover& resp ) { + [this, editor]( const Int64&, const LSPHover& resp ) { if ( editorExists( editor ) && !resp.contents.empty() && !resp.contents[0].value.empty() ) { - editor->runOnMainThread( [editor, resp, position, this]() { - if ( !editor->getScreenRect().contains( editor->getUISceneNode() - ->getWindow() - ->getInput() - ->getMousePos() - .asFloat() ) ) + editor->runOnMainThread( [editor, resp, this]() { + auto mousePos = + editor->getUISceneNode()->getWindow()->getInput()->getMousePos(); + if ( !editor->getScreenRect().contains( mousePos.asFloat() ) ) return; - tryDisplayTooltip( editor, resp, position ); + tryDisplayTooltip( editor, resp, mousePos ); } ); } } ); }, - mHoverDelay, tag ); + mHoverDelay, getMouseMoveHash( editor ) ); tryHideTooltip( editor, position ); return editor->getTooltip() && editor->getTooltip()->isVisible() && mSymbolInfoShowing; } diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.hpp b/src/tools/ecode/plugins/lsp/lspclientplugin.hpp index 0dc1082fa..72677044a 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.hpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.hpp @@ -110,7 +110,6 @@ class LSPClientPlugin : public Plugin { Mutex mDocSymbolsMutex; Mutex mDocCurrentSymbolsMutex; UnorderedMap> mEditors; - UnorderedMap> mEditorsTags; UnorderedSet mDocs; UnorderedMap mDocSymbols; UnorderedMap mDocFlatSymbols;