From ffbf3a91d7d69c687f25193ed7941b38eaf8eead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Sun, 22 Sep 2024 21:16:01 -0300 Subject: [PATCH] Clean up a little bit. Added options to RegEx. Fix case insensitive search with RegEx. Added RegEx to UIDocFindReplace. --- include/eepp/system/regex.hpp | 41 ++++++++++--- include/eepp/ui/tools/uidocfindreplace.hpp | 17 +++--- include/eepp/ui/uidatabind.hpp | 2 + src/eepp/system/regex.cpp | 35 +++++------ src/eepp/ui/doc/textdocument.cpp | 47 +++++++++------ src/eepp/ui/tools/uidocfindreplace.cpp | 61 +++++++++++++------- src/tools/ecode/globalsearchcontroller.cpp | 8 +-- src/tools/ecode/projectsearch.cpp | 67 +++++----------------- src/tools/ecode/projectsearch.hpp | 11 ++-- 9 files changed, 148 insertions(+), 141 deletions(-) diff --git a/include/eepp/system/regex.hpp b/include/eepp/system/regex.hpp index 15620052c..18db83362 100644 --- a/include/eepp/system/regex.hpp +++ b/include/eepp/system/regex.hpp @@ -16,9 +16,9 @@ class EE_API RegExCache { void setEnabled( bool enabled ); - void insert( std::string_view, void* cache ); + void insert( std::string_view, Uint32 options, void* cache ); - void* find( const std::string_view& ); + void* find( const std::string_view&, Uint32 options ); void clear(); @@ -29,7 +29,38 @@ class EE_API RegExCache { class EE_API RegEx : public PatternMatcher { public: - RegEx( const std::string_view& pattern, bool useCache = true ); + enum Options : Uint32 { + None = 0x00000000u, + AllowEmptyClass = 0x00000001u, // C + AltBsux = 0x00000002u, // C + AutoCallout = 0x00000004u, // C + Caseless = 0x00000008u, // C + DollarEndonly = 0x00000010u, // J M D + Dotall = 0x00000020u, // C + Dupnames = 0x00000040u, // C + Extended = 0x00000080u, // C + Firstline = 0x00000100u, // J M D + MatchUnsetBackref = 0x00000200u, // C J M + Multiline = 0x00000400u, // C + NeverUcp = 0x00000800u, // C + NeverUtf = 0x00001000u, // C + NoAutoCapture = 0x00002000u, // C + NoAutoPossess = 0x00004000u, // C + NoDotstarAnchor = 0x00008000u, // C + NoStartOptimize = 0x00010000u, // J M D + Ucp = 0x00020000u, // C J M D + Ungreedy = 0x00040000u, // C + Utf = 0x00080000u, // C J M D + NeverBackslashC = 0x00100000u, // C + AltCircumflex = 0x00200000u, // J M D + AltVerbnames = 0x00400000u, // C + UseOffsetLimit = 0x00800000u, // J M D + ExtendedMore = 0x01000000u, // C + Literal = 0x02000000u, // C + MatchInvalidUtf = 0x04000000u, // J M D + }; + + RegEx( const std::string_view& pattern, Options options = Options::Utf, bool useCache = true ); virtual ~RegEx(); @@ -52,10 +83,6 @@ class EE_API RegEx : public PatternMatcher { int mCaptureCount; bool mValid{ false }; bool mCached{ false }; - - RegEx( const std::string_view& pattern, bool useCache, bool init ); - - void init( const std::string_view& pattern, bool useCache ); }; }} // namespace EE::System diff --git a/include/eepp/ui/tools/uidocfindreplace.hpp b/include/eepp/ui/tools/uidocfindreplace.hpp index d9928046c..9e506d09d 100644 --- a/include/eepp/ui/tools/uidocfindreplace.hpp +++ b/include/eepp/ui/tools/uidocfindreplace.hpp @@ -15,15 +15,11 @@ namespace EE { namespace UI { namespace Tools { class EE_API UIDocFindReplace : public UILinearLayout, public WidgetCommandExecuter { public: static std::unordered_map getDefaultKeybindings() { - return { { "mod+g", "repeat-find" }, - { "escape", "close-find-replace" }, - { "mod+r", "replace-selection" }, - { "mod+shift+n", "find-and-replace" }, - { "mod+shift+r", "replace-all" }, - { "mod+s", "change-case" }, - { "mod+w", "change-whole-word" }, - { "mod+l", "toggle-lua-pattern" }, - { "mod+e", "change-escape-sequence" }, + return { { "mod+g", "repeat-find" }, { "escape", "close-find-replace" }, + { "mod+r", "replace-selection" }, { "mod+shift+n", "find-and-replace" }, + { "mod+shift+r", "replace-all" }, { "mod+s", "change-case" }, + { "mod+w", "change-whole-word" }, { "mod+p", "toggle-regex" }, + { "mod+l", "toggle-lua-pattern" }, { "mod+e", "change-escape-sequence" }, { "mod+shift+g", "find-prev" } }; } @@ -46,18 +42,19 @@ class EE_API UIDocFindReplace : public UILinearLayout, public WidgetCommandExecu protected: bool mReady{ false }; bool mReplaceDisabled{ false }; + bool mChangingPattern{ false }; UIWidget* mFindReplaceToggle{ nullptr }; UITextInput* mFindInput{ nullptr }; UITextInput* mReplaceInput{ nullptr }; UISelectButton* mCaseSensitive{ nullptr }; UISelectButton* mLuaPattern{ nullptr }; + UISelectButton* mRegEx{ nullptr }; UISelectButton* mWholeWord{ nullptr }; UISelectButton* mEscapeSequences{ nullptr }; UIWidget* mToggle{ nullptr }; UIWidget* mReplaceBox{ nullptr }; std::shared_ptr mDoc; std::vector>> mDataBinds; - std::unique_ptr> mPatternBind; UIDocFindReplace( UIWidget* parent, const std::shared_ptr& doc, diff --git a/include/eepp/ui/uidatabind.hpp b/include/eepp/ui/uidatabind.hpp index 8be79307c..06d0c6ac9 100644 --- a/include/eepp/ui/uidatabind.hpp +++ b/include/eepp/ui/uidatabind.hpp @@ -151,6 +151,8 @@ template class UIDataBind { std::function onValueChangeCb; + const std::set& getWidgets() const { return widgets; } + protected: T* data{ nullptr }; std::set widgets; diff --git a/src/eepp/system/regex.cpp b/src/eepp/system/regex.cpp index 167600806..a25fd329c 100644 --- a/src/eepp/system/regex.cpp +++ b/src/eepp/system/regex.cpp @@ -9,12 +9,12 @@ RegExCache::~RegExCache() { clear(); } -void RegExCache::insert( std::string_view key, void* cache ) { - mCache.insert( { String::hash( key ), cache } ); +void RegExCache::insert( std::string_view key, Uint32 options, void* cache ) { + mCache.insert( { hashCombine( String::hash( key ), options ), cache } ); } -void* RegExCache::find( const std::string_view& key ) { - auto it = mCache.find( String::hash( key ) ); +void* RegExCache::find( const std::string_view& key, Uint32 options ) { + auto it = mCache.find( hashCombine( String::hash( key ), options ) ); return ( it != mCache.end() ) ? it->second : nullptr; } @@ -24,32 +24,19 @@ void RegExCache::clear() { mCache.clear(); } -RegEx::RegEx( const std::string_view& pattern, bool useCache, bool initRegEx ) : +RegEx::RegEx( const std::string_view& pattern, Options options, bool useCache ) : PatternMatcher( PatternType::PCRE ), mPattern( pattern ), mMatchNum( 0 ), mCompiledPattern( nullptr ), mCaptureCount( 0 ), mValid( true ) { - if ( initRegEx ) - init( pattern, useCache ); -} - -RegEx::RegEx( const std::string_view& pattern, bool useCache ) : RegEx( pattern, useCache, true ) {} - -RegEx::~RegEx() { - if ( !mCached && mCompiledPattern != nullptr ) { - pcre2_code_free( reinterpret_cast( mCompiledPattern ) ); - } -} - -void RegEx::init( const std::string_view& pattern, bool useCache ) { int errornumber; PCRE2_SIZE erroroffset; PCRE2_SPTR pattern_sptr = reinterpret_cast( pattern.data() ); if ( useCache && RegExCache::instance()->isEnabled() && - ( mCompiledPattern = RegExCache::instance()->find( pattern ) ) ) { + ( mCompiledPattern = RegExCache::instance()->find( pattern, options ) ) ) { mValid = true; mCached = true; return; @@ -57,7 +44,7 @@ void RegEx::init( const std::string_view& pattern, bool useCache ) { mCompiledPattern = pcre2_compile( pattern_sptr, // the pattern pattern.size(), // the length of the pattern - PCRE2_UTF, // default options + options, // default options &errornumber, // for error number &erroroffset, // for error offset NULL // use default compile context @@ -81,11 +68,17 @@ void RegEx::init( const std::string_view& pattern, bool useCache ) { // std::to_string( rc ) ); mValid = false; } else if ( useCache && RegExCache::instance()->isEnabled() ) { - RegExCache::instance()->insert( pattern, mCompiledPattern ); + RegExCache::instance()->insert( pattern, options, mCompiledPattern ); mCached = true; } } +RegEx::~RegEx() { + if ( !mCached && mCompiledPattern != nullptr ) { + pcre2_code_free( reinterpret_cast( mCompiledPattern ) ); + } +} + bool RegEx::matches( const char* stringSearch, int stringStartOffset, PatternMatcher::Range* matchList, size_t stringLength ) const { auto* compiledPattern = reinterpret_cast( mCompiledPattern ); diff --git a/src/eepp/ui/doc/textdocument.cpp b/src/eepp/ui/doc/textdocument.cpp index 64a76c11c..85e9734ef 100644 --- a/src/eepp/ui/doc/textdocument.cpp +++ b/src/eepp/ui/doc/textdocument.cpp @@ -2433,10 +2433,14 @@ struct FindTypeResult { }; static FindTypeResult findType( const String& str, const String& findStr, - const TextDocument::FindReplaceType& type, int colOffset ) { + const TextDocument::FindReplaceType& type, int colOffset, + bool caseSensitive ) { switch ( type ) { case TextDocument::FindReplaceType::RegEx: { - RegEx words( findStr.toUtf8() ); + RegEx words( findStr.toUtf8(), + static_cast( RegEx::Options::Utf | + ( !caseSensitive ? RegEx::Options::Caseless + : RegEx::Options::None ) ) ); if ( !words.isValid() ) return { String::StringType::npos, String::StringType::npos }; RegEx::Range matches[MAX_CAPTURES]; @@ -2484,11 +2488,15 @@ static FindTypeResult findType( const String& str, const String& findStr, } static FindTypeResult findLastType( const String& str, const String& findStr, - const TextDocument::FindReplaceType& type ) { + const TextDocument::FindReplaceType& type, + bool caseSensitive ) { switch ( type ) { case TextDocument::FindReplaceType::RegEx: { // TODO: Implement findLastType for Lua patterns - RegEx words( findStr.toUtf8() ); + RegEx words( findStr.toUtf8(), + static_cast( RegEx::Options::Utf | + ( !caseSensitive ? RegEx::Options::Caseless + : RegEx::Options::None ) ) ); if ( !words.isValid() ) return { String::StringType::npos, String::StringType::npos }; RegEx::Range matches[MAX_CAPTURES]; @@ -2567,6 +2575,7 @@ TextDocument::SearchResult TextDocument::findText( String text, TextPosition fro return TextDocument::SearchResult{}; } + bool realCaseSensitive = caseSensitive; if ( ( type == FindReplaceType::LuaPattern || type == FindReplaceType::RegEx ) && caseSensitive == false ) { caseSensitive = @@ -2584,24 +2593,26 @@ TextDocument::SearchResult TextDocument::findText( String text, TextPosition fro from.line() == to.line() ? to.column() - from.column() : String::InvalidPos ), - text, type, from.column() ) + text, type, from.column(), realCaseSensitive ) : findType( String::toLower( line( i ).getText() ) .substr( from.column(), from.line() == to.line() ? to.column() - from.column() : String::InvalidPos ), - text, type, from.column() ); + text, type, from.column(), realCaseSensitive ); if ( String::StringType::npos != col.start ) { col.start += from.column(); col.end += from.column(); } } else if ( i == to.line() && to != endOfDoc() ) { col = caseSensitive - ? findType( line( i ).getText().substr( 0, to.column() ), text, type, 0 ) + ? findType( line( i ).getText().substr( 0, to.column() ), text, type, 0, + realCaseSensitive ) : findType( String::toLower( line( i ).getText() ).substr( 0, to.column() ), - text, type, 0 ); + text, type, 0, realCaseSensitive ); } else { - col = caseSensitive ? findType( line( i ).getText(), text, type, 0 ) - : findType( String::toLower( line( i ).getText() ), text, type, 0 ); + col = caseSensitive ? findType( line( i ).getText(), text, type, 0, realCaseSensitive ) + : findType( String::toLower( line( i ).getText() ), text, type, 0, + realCaseSensitive ); } if ( String::StringType::npos != col.start && ( !wholeWord || String::isWholeWord( line( i ).getText(), text, col.start ) ) ) { @@ -2627,6 +2638,7 @@ TextDocument::SearchResult TextDocument::findTextLast( String text, TextPosition return TextDocument::SearchResult{}; } + bool realCaseSensitive = caseSensitive; if ( ( type == FindReplaceType::LuaPattern || type == FindReplaceType::RegEx ) && caseSensitive == false ) { caseSensitive = @@ -2643,24 +2655,25 @@ TextDocument::SearchResult TextDocument::findTextLast( String text, TextPosition caseSensitive ? findLastType( line( i ).getText().substr( from.line() == to.line() ? to.column() : 0, from.column() ), - text, type ) + text, type, realCaseSensitive ) : findLastType( String::toLower( line( i ).getText().substr( from.line() == to.line() ? to.column() : 0, from.column() ) ), - text, type ); + text, type, realCaseSensitive ); } else if ( i == to.line() ) { res = caseSensitive - ? findLastType( line( i ).getText().substr( to.column() ), text, type ) + ? findLastType( line( i ).getText().substr( to.column() ), text, type, + realCaseSensitive ) : findLastType( String::toLower( line( i ).getText().substr( to.column() ) ), - text, type ); + text, type, realCaseSensitive ); if ( String::StringType::npos != res.start ) { res.start += to.column(); res.end += to.column(); } } else { - res = caseSensitive - ? findLastType( line( i ).getText(), text, type ) - : findLastType( String::toLower( line( i ).getText() ), text, type ); + res = caseSensitive ? findLastType( line( i ).getText(), text, type, realCaseSensitive ) + : findLastType( String::toLower( line( i ).getText() ), text, type, + realCaseSensitive ); } if ( String::StringType::npos != res.start && ( !wholeWord || String::isWholeWord( line( i ).getText(), text, res.start ) ) ) { diff --git a/src/eepp/ui/tools/uidocfindreplace.cpp b/src/eepp/ui/tools/uidocfindreplace.cpp index df7a190f0..968508d0a 100644 --- a/src/eepp/ui/tools/uidocfindreplace.cpp +++ b/src/eepp/ui/tools/uidocfindreplace.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -80,6 +81,9 @@ const char DOC_FIND_REPLACE_CSS[] = R"css( .ce_find_replace_box selectbutton.match-case { icon: url("data:image/svg,"); } +.ce_find_replace_box selectbutton.luapattern { + icon: url("data:image/svg,"); +} .ce_find_replace_box selectbutton.regex { icon: url("data:image/svg,"); } @@ -107,7 +111,7 @@ const char DOC_FIND_REPLACE_XML[] = R"xml(