From dccd0617e5181f7ac57207b41805ab981ded4688 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Wed, 23 Dec 2020 02:46:46 -0300 Subject: [PATCH] Fixed UITabWidget clipping. Added pyw extension for python files. ecode: Added: Hide tabbar on single tab option. Added whole word search in global search. Some minor fixes in global search. --- .../eepp/ui/tools/uicodeeditorsplitter.hpp | 7 ++ src/eepp/ui/doc/syntaxdefinitionmanager.cpp | 2 +- src/eepp/ui/tools/uicodeeditorsplitter.cpp | 20 +++- src/eepp/ui/uitabwidget.cpp | 2 +- src/tools/codeeditor/appconfig.cpp | 2 + src/tools/codeeditor/appconfig.hpp | 1 + src/tools/codeeditor/codeeditor.cpp | 28 +++++- src/tools/codeeditor/codeeditor.hpp | 1 + src/tools/codeeditor/projectsearch.cpp | 97 ++++++------------- src/tools/codeeditor/projectsearch.hpp | 19 ++-- .../codeeditor/uitreeviewglobalsearch.cpp | 10 +- 11 files changed, 100 insertions(+), 89 deletions(-) diff --git a/include/eepp/ui/tools/uicodeeditorsplitter.hpp b/include/eepp/ui/tools/uicodeeditorsplitter.hpp index bf19c5e97..b832d8d8a 100644 --- a/include/eepp/ui/tools/uicodeeditorsplitter.hpp +++ b/include/eepp/ui/tools/uicodeeditorsplitter.hpp @@ -89,6 +89,8 @@ class EE_API UICodeEditorSplitter { void forEachDoc( std::function run ); + void forEachTabWidget( std::function run ); + void zoomIn(); void zoomOut(); @@ -121,6 +123,10 @@ class EE_API UICodeEditorSplitter { void forEachDocStoppable( std::function run ); + bool getHideTabBarOnSingleTab() const; + + void setHideTabBarOnSingleTab( bool hideTabBarOnSingleTab ); + protected: UISceneNode* mUISceneNode{ nullptr }; UICodeEditor* mCurEditor{ nullptr }; @@ -128,6 +134,7 @@ class EE_API UICodeEditorSplitter { std::string mCurrentColorScheme; std::vector mTabWidgets; Client* mClient; + bool mHideTabBarOnSingleTab{ true }; UICodeEditorSplitter( UICodeEditorSplitter::Client* client, UISceneNode* sceneNode, const std::vector& colorSchemes, diff --git a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp index 6ccaf3e81..d30f9d52b 100644 --- a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp +++ b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp @@ -186,7 +186,7 @@ SyntaxDefinitionManager::SyntaxDefinitionManager() { // Python add( { "Python", - { "%.py$" }, + { "%.py$", "%.pyw$" }, { { { "#", "\n" }, "comment" }, { { "[ruU]?\"", "\"", "\\" }, "string" }, diff --git a/src/eepp/ui/tools/uicodeeditorsplitter.cpp b/src/eepp/ui/tools/uicodeeditorsplitter.cpp index 25f35b969..caf7e8448 100644 --- a/src/eepp/ui/tools/uicodeeditorsplitter.cpp +++ b/src/eepp/ui/tools/uicodeeditorsplitter.cpp @@ -352,7 +352,7 @@ UITabWidget* UICodeEditorSplitter::createEditorWithTabWidget( Node* parent ) { tabWidget->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent ); tabWidget->setParent( parent ); tabWidget->setTabsClosable( true ); - tabWidget->setHideTabBarOnSingleTab( true ); + tabWidget->setHideTabBarOnSingleTab( mHideTabBarOnSingleTab ); tabWidget->setAllowRearrangeTabs( true ); tabWidget->setAllowDragAndDropTabs( true ); tabWidget->addEventListener( Event::OnTabSelected, [&]( const Event* event ) { @@ -408,6 +408,11 @@ void UICodeEditorSplitter::forEachDoc( std::function run run( *doc ); } +void UICodeEditorSplitter::forEachTabWidget( std::function run ) { + for ( auto widget : mTabWidgets ) + run( widget ); +} + void UICodeEditorSplitter::forEachEditorStoppable( std::function run ) { for ( auto tabWidget : mTabWidgets ) { for ( size_t i = 0; i < tabWidget->getTabCount(); i++ ) { @@ -432,6 +437,19 @@ void UICodeEditorSplitter::forEachDocStoppable( std::functionsetHideTabBarOnSingleTab( hideTabBarOnSingleTab ); + } +} + std::vector UICodeEditorSplitter::getAllEditors() { std::vector editors; forEachEditor( [&]( UICodeEditor* editor ) { editors.push_back( editor ); } ); diff --git a/src/eepp/ui/uitabwidget.cpp b/src/eepp/ui/uitabwidget.cpp index 357eb561c..66943365b 100644 --- a/src/eepp/ui/uitabwidget.cpp +++ b/src/eepp/ui/uitabwidget.cpp @@ -25,6 +25,7 @@ UITabWidget::UITabWidget() : mAllowDragAndDropTabs( false ), mTabVerticalDragResistance( PixelDensity::dpToPx( 64 ) ) { setHorizontalAlign( UI_HALIGN_CENTER ); + clipEnable(); mTabBar = UIWidget::NewWithTag( "tabwidget::tabbar" ); mTabBar->setPixelsSize( mSize.getWidth(), mStyleConfig.TabHeight ) @@ -37,7 +38,6 @@ UITabWidget::UITabWidget() : mSize.getHeight() - PixelDensity::dpToPx( mStyleConfig.TabHeight ) ) ->setParent( this ) ->setPosition( 0, mStyleConfig.TabHeight ); - mNodeContainer->clipEnable(); mTabScroll = UIScrollBar::NewHorizontalWithTag( "scrollbarmini" ); mTabScroll->setParent( this ); diff --git a/src/tools/codeeditor/appconfig.cpp b/src/tools/codeeditor/appconfig.cpp index 07509ef9d..d557e5cb7 100644 --- a/src/tools/codeeditor/appconfig.cpp +++ b/src/tools/codeeditor/appconfig.cpp @@ -71,6 +71,7 @@ void AppConfig::load( std::string& confPath, std::string& keybindingsPath, editor.autoComplete = ini.getValueB( "editor", "auto_complete", true ); editor.linter = ini.getValueB( "editor", "linter", true ); editor.showDocInfo = ini.getValueB( "editor", "show_doc_info", true ); + editor.hideTabBarOnSingleTab = ini.getValueB( "editor", "hide_tab_bar_on_single_tab", true ); } void AppConfig::save( const std::vector& recentFiles, @@ -115,6 +116,7 @@ void AppConfig::save( const std::vector& recentFiles, ini.setValueB( "editor", "auto_complete", editor.autoComplete ); ini.setValueB( "editor", "linter", editor.linter ); ini.setValueB( "editor", "show_doc_info", editor.showDocInfo ); + ini.setValueB( "editor", "hide_tab_bar_on_single_tab", editor.hideTabBarOnSingleTab ); ini.writeFile(); iniState.writeFile(); } diff --git a/src/tools/codeeditor/appconfig.hpp b/src/tools/codeeditor/appconfig.hpp index 7d0f181e7..5f6f79553 100644 --- a/src/tools/codeeditor/appconfig.hpp +++ b/src/tools/codeeditor/appconfig.hpp @@ -51,6 +51,7 @@ struct CodeEditorConfig { bool autoComplete{ true }; bool showDocInfo{ true }; bool linter{ true }; + bool hideTabBarOnSingleTab{ true }; std::string autoCloseBrackets{ "" }; int indentWidth{ 4 }; int tabWidth{ 4 }; diff --git a/src/tools/codeeditor/codeeditor.cpp b/src/tools/codeeditor/codeeditor.cpp index 3d9f6aaa6..e2aba27f9 100644 --- a/src/tools/codeeditor/codeeditor.cpp +++ b/src/tools/codeeditor/codeeditor.cpp @@ -582,6 +582,7 @@ void App::initSearchBar() { UITextInput* findInput = mSearchBarLayout->find( "search_find" ); UITextInput* replaceInput = mSearchBarLayout->find( "search_replace" ); UICheckBox* caseSensitiveChk = mSearchBarLayout->find( "case_sensitive" ); + UICheckBox* wholeWordChk = mSearchBarLayout->find( "whole_word" ); findInput->addEventListener( Event::OnTextChanged, [&, findInput]( const Event* ) { if ( mSearchState.editor && mEditorSplitter->editorExists( mSearchState.editor ) ) { mSearchState.text = findInput->getText(); @@ -627,12 +628,17 @@ void App::initSearchBar() { caseSensitiveChk->setChecked( !caseSensitiveChk->isChecked() ); mSearchState.caseSensitive = caseSensitiveChk->isChecked(); } ); + mSearchBarLayout->addCommand( "change-whole-word", [&, wholeWordChk] { + wholeWordChk->setChecked( !wholeWordChk->isChecked() ); + mSearchState.wholeWord = wholeWordChk->isChecked(); + } ); mSearchBarLayout->getKeyBindings().addKeybindsString( { { "f3", "repeat-find" }, { "ctrl+g", "repeat-find" }, { "escape", "close-searchbar" }, { "ctrl+r", "replace-all" }, { "ctrl+s", "change-case" }, + { "ctrl+w", "change-whole-word" }, } ); addReturnListener( findInput, "repeat-find" ); addReturnListener( replaceInput, "find-and-replace" ); @@ -704,11 +710,12 @@ void App::initGlobalSearchBar() { }; UIPushButton* searchButton = mGlobalSearchBarLayout->find( "global_search" ); UICheckBox* caseSensitiveChk = mGlobalSearchBarLayout->find( "case_sensitive" ); + UICheckBox* wholeWordChk = mGlobalSearchBarLayout->find( "whole_word" ); UIWidget* searchBarClose = mGlobalSearchBarLayout->find( "global_searchbar_close" ); mGlobalSearchInput = mGlobalSearchBarLayout->find( "global_search_find" ); mGlobalSearchHistoryList = mGlobalSearchBarLayout->find( "global_search_history" ); - mGlobalSearchBarLayout->addCommand( "search-in-files", [&, caseSensitiveChk] { + mGlobalSearchBarLayout->addCommand( "search-in-files", [&, caseSensitiveChk, wholeWordChk] { if ( mDirTree && mDirTree->getFilesCount() > 0 && !mGlobalSearchInput->getText().empty() ) { UILoader* loader = UILoader::New(); loader->setId( "loader" ); @@ -720,7 +727,7 @@ void App::initGlobalSearchBar() { mGlobalSearchTree->getSize() * 0.5f - loader->getSize() * 0.5f ); Clock* clock = eeNew( Clock, () ); std::string search( mGlobalSearchInput->getText().toUtf8() ); - ProjectSearch::findHorspool( + ProjectSearch::find( mDirTree->getFiles(), search, #if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN || defined( __EMSCRIPTEN_PTHREADS__ ) mThreadPool, @@ -763,7 +770,7 @@ void App::initGlobalSearchBar() { loader->close(); } ); }, - caseSensitiveChk->isChecked() ); + caseSensitiveChk->isChecked(), wholeWordChk->isChecked() ); } } ); mGlobalSearchBarLayout->addCommand( "close-global-searchbar", [&] { @@ -774,10 +781,14 @@ void App::initGlobalSearchBar() { mGlobalSearchBarLayout->getKeyBindings().addKeybindsString( { { "escape", "close-global-searchbar" }, { "ctrl+s", "change-case" }, + { "ctrl+w", "change-whole-word" }, } ); mGlobalSearchBarLayout->addCommand( "change-case", [&, caseSensitiveChk] { caseSensitiveChk->setChecked( !caseSensitiveChk->isChecked() ); } ); + mGlobalSearchBarLayout->addCommand( "change-whole-word", [&, wholeWordChk] { + wholeWordChk->setChecked( !wholeWordChk->isChecked() ); + } ); mGlobalSearchInput->addEventListener( Event::OnPressEnter, [&]( const Event* ) { if ( mGlobalSearchInput->hasFocus() ) { mGlobalSearchBarLayout->execute( "search-in-files" ); @@ -863,6 +874,7 @@ void App::showFindView() { mSearchState.range = TextRange(); mSearchState.caseSensitive = mSearchBarLayout->find( "case_sensitive" )->isChecked(); + mSearchState.wholeWord = mSearchBarLayout->find( "whole_word" )->isChecked(); mSearchBarLayout->setEnabled( true )->setVisible( true ); UITextInput* findInput = mSearchBarLayout->find( "search_find" ); @@ -1186,6 +1198,9 @@ UIMenu* App::createViewMenu() { ->setActive( mConfig.editor.linter ) ->setTooltipText( "Use static code analysis tool used to flag programming errors, bugs,\n" "stylistic errors, and suspicious constructs." ); + mViewMenu->addCheckBox( "Hide tabbar on single tab" ) + ->setActive( mConfig.editor.hideTabBarOnSingleTab ) + ->setTooltipText( "Hides the tabbar if there's only one element in the tab widget." ); mViewMenu->add( "Line Breaking Column" ); mViewMenu->addEventListener( Event::OnItemClicked, [&]( const Event* event ) { @@ -1242,7 +1257,9 @@ UIMenu* App::createViewMenu() { mDocInfo->setVisible( mConfig.editor.showDocInfo ); if ( mEditorSplitter->getCurEditor() ) updateDocInfo( mEditorSplitter->getCurEditor()->getDocument() ); - + } else if ( item->getText() == "Hide tabbar on single tab" ) { + mConfig.editor.hideTabBarOnSingleTab = item->asType()->isActive(); + mEditorSplitter->setHideTabBarOnSingleTab( mConfig.editor.hideTabBarOnSingleTab ); } else if ( item->getText() == "Line Breaking Column" ) { UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::INPUT, "Set Line Breaking Column:\n" @@ -2439,6 +2456,7 @@ void App::init( const std::string& file, const Float& pidelDensity ) { + @@ -2461,6 +2479,7 @@ void App::init( const std::string& file, const Float& pidelDensity ) { + @@ -2551,6 +2570,7 @@ void App::init( const std::string& file, const Float& pidelDensity ) { this, mUISceneNode, SyntaxColorScheme::loadFromFile( mResPath + "assets/colorschemes/colorschemes.conf" ), mInitColorScheme ); + mEditorSplitter->setHideTabBarOnSingleTab( mConfig.editor.hideTabBarOnSingleTab ); #if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN mFileWatcher = new efsw::FileWatcher(); diff --git a/src/tools/codeeditor/codeeditor.hpp b/src/tools/codeeditor/codeeditor.hpp index 71a17d27b..f66ad3bb8 100644 --- a/src/tools/codeeditor/codeeditor.hpp +++ b/src/tools/codeeditor/codeeditor.hpp @@ -86,6 +86,7 @@ struct SearchState { String text; TextRange range = TextRange(); bool caseSensitive{ false }; + bool wholeWord{ false }; void reset() { editor = nullptr; range = TextRange(); diff --git a/src/tools/codeeditor/projectsearch.cpp b/src/tools/codeeditor/projectsearch.cpp index b55da1c9d..6a1af0e9f 100644 --- a/src/tools/codeeditor/projectsearch.cpp +++ b/src/tools/codeeditor/projectsearch.cpp @@ -15,7 +15,7 @@ static int countNewLines( const std::string& text, const size_t& start, const si return count; } -static std::string textLine( const std::string& fileText, const size_t& fromPos, size_t& relCol ) { +static String textLine( const std::string& fileText, const size_t& fromPos, size_t& relCol ) { size_t start = 0; size_t end = 0; const char* stringStartPtr = fileText.c_str(); @@ -29,13 +29,20 @@ static std::string textLine( const std::string& fileText, const size_t& fromPos, while ( ++ptr && *ptr != '\0' && *ptr != '\n' ) { } end = ptr - stringStartPtr; - relCol = startPtr - nlStartPtr; + relCol = String( fileText.substr( start, startPtr - nlStartPtr ) ).size(); return fileText.substr( start, end - start ); } +static bool isWholeWord( const std::string& fileText, const std::string& text, + const Int64& searchRes ) { + return ( 0 == searchRes || !( std::isalnum( fileText[searchRes - 1] ) ) ) && + ( searchRes + text.size() >= fileText.size() || + !( std::isalnum( fileText[searchRes + text.size()] ) ) ); +} + static std::vector searchInFileHorspool( const std::string& file, const std::string& text, const bool& caseSensitive, - const String::BMH::OccTable& occ ) { + const bool& wholeWord, const String::BMH::OccTable& occ ) { std::vector res; std::string fileText; Int64 lSearchRes = 0; @@ -48,10 +55,15 @@ searchInFileHorspool( const std::string& file, const std::string& text, const bo do { searchRes = String::BMH::find( fileText, text, searchRes, occ ); if ( searchRes != -1 ) { + if ( wholeWord && !isWholeWord( fileText, text, searchRes ) ) { + lSearchRes = searchRes; + searchRes += text.size(); + continue; + } TextPosition pos; size_t relCol; totNl += countNewLines( fileText, lSearchRes, searchRes ); - std::string str = textLine( fileTextOriginal, searchRes, relCol ); + String str( textLine( fileTextOriginal, searchRes, relCol ) ); pos.setLine( totNl ); pos.setColumn( relCol ); res.push_back( { str, pos } ); @@ -63,6 +75,11 @@ searchInFileHorspool( const std::string& file, const std::string& text, const bo do { searchRes = String::BMH::find( fileText, text, searchRes, occ ); if ( searchRes != -1 ) { + if ( wholeWord && !isWholeWord( fileText, text, searchRes ) ) { + lSearchRes = searchRes; + searchRes += text.size(); + continue; + } TextPosition pos; size_t relCol; totNl += countNewLines( fileText, lSearchRes, searchRes ); @@ -78,43 +95,13 @@ searchInFileHorspool( const std::string& file, const std::string& text, const bo return res; } -static std::vector -searchInFile( const std::string& file, const std::string& text, const bool& caseSensitive ) { - std::vector res; - TextDocument doc( false ); - TextPosition pos{ 0, 0 }; - String searchText( text ); - if ( doc.loadFromFile( file ) ) { - do { - pos = doc.find( searchText, pos, caseSensitive ); - if ( pos.isValid() ) { - const auto& l = doc.line( pos.line() ).getText(); - res.push_back( { l.substr( 0, l.size() - 1 ).toUtf8(), pos } ); - pos = doc.positionOffset( pos, searchText.size() ); - } - } while ( pos.isValid() ); - } - return res; -} - void ProjectSearch::find( const std::vector files, const std::string& string, - ResultCb result, bool caseSensitive ) { - Result res; - for ( auto& file : files ) { - auto fileRes = searchInFile( file, string, caseSensitive ); - if ( !fileRes.empty() ) - res.push_back( { file, fileRes } ); - } - result( res ); -} - -void ProjectSearch::findHorspool( const std::vector files, const std::string& string, - ResultCb result, bool caseSensitive ) { + ResultCb result, bool caseSensitive, bool wholeWord ) { Result res; const auto occ = String::BMH::createOccTable( (const unsigned char*)string.c_str(), string.size() ); for ( auto& file : files ) { - auto fileRes = searchInFileHorspool( file, string, caseSensitive, occ ); + auto fileRes = searchInFileHorspool( file, string, caseSensitive, wholeWord, occ ); if ( !fileRes.empty() ) res.push_back( { file, fileRes } ); } @@ -129,38 +116,8 @@ struct FindData { }; void ProjectSearch::find( const std::vector files, std::string string, - std::shared_ptr pool, ResultCb result, bool caseSensitive ) { - if ( files.empty() ) - result( {} ); - FindData* findData = eeNew( FindData, () ); - findData->resCount = files.size(); - for ( auto& file : files ) { - pool->run( - [findData, file, string, caseSensitive] { - auto fileRes = searchInFile( file, string, caseSensitive ); - if ( !fileRes.empty() ) { - Lock l( findData->resMutex ); - findData->res.push_back( { file, fileRes } ); - } - }, - [result, findData] { - int count; - { - Lock l( findData->countMutex ); - findData->resCount--; - count = findData->resCount; - } - if ( count == 0 ) { - result( findData->res ); - eeDelete( findData ); - } - } ); - } -} - -void ProjectSearch::findHorspool( const std::vector files, std::string string, - std::shared_ptr pool, ResultCb result, - bool caseSensitive ) { + std::shared_ptr pool, ResultCb result, bool caseSensitive, + bool wholeWord ) { if ( files.empty() ) result( {} ); FindData* findData = eeNew( FindData, () ); @@ -171,8 +128,8 @@ void ProjectSearch::findHorspool( const std::vector files, std::str String::BMH::createOccTable( (const unsigned char*)string.c_str(), string.size() ); for ( auto& file : files ) { pool->run( - [findData, file, string, caseSensitive, occ] { - auto fileRes = searchInFileHorspool( file, string, caseSensitive, occ ); + [findData, file, string, caseSensitive, wholeWord, occ] { + auto fileRes = searchInFileHorspool( file, string, caseSensitive, wholeWord, occ ); if ( !fileRes.empty() ) { Lock l( findData->resMutex ); findData->res.push_back( { file, fileRes } ); diff --git a/src/tools/codeeditor/projectsearch.hpp b/src/tools/codeeditor/projectsearch.hpp index d7a3ca0ca..791201f3c 100644 --- a/src/tools/codeeditor/projectsearch.hpp +++ b/src/tools/codeeditor/projectsearch.hpp @@ -19,7 +19,7 @@ class ProjectSearch { struct ResultData { struct Result { Result( const String& line, const TextPosition& pos ) : line( line ), position( pos ) {} - std::string line; + String line; TextPosition position; }; std::string file; @@ -85,7 +85,10 @@ class ProjectSearch { "%6lld %s", mResult[index.internalId()].results[index.row()].position.line() + 1, - mResult[index.internalId()].results[index.row()].line.c_str() ) ); + mResult[index.internalId()] + .results[index.row()] + .line.toUtf8() + .c_str() ) ); } } } else if ( role == Role::Custom ) { @@ -123,17 +126,11 @@ class ProjectSearch { } static void find( const std::vector files, const std::string& string, - ResultCb result, bool caseSensitive ); + ResultCb result, bool caseSensitive, bool wholeWord = false ); static void find( const std::vector files, std::string string, - std::shared_ptr pool, ResultCb result, bool caseSensitive ); - - static void findHorspool( const std::vector files, const std::string& string, - ResultCb result, bool caseSensitive ); - - static void findHorspool( const std::vector files, std::string string, - std::shared_ptr pool, ResultCb result, - bool caseSensitive ); + std::shared_ptr pool, ResultCb result, bool caseSensitive, + bool wholeWord = false ); }; #endif // PROJECTSEARCH_HPP diff --git a/src/tools/codeeditor/uitreeviewglobalsearch.cpp b/src/tools/codeeditor/uitreeviewglobalsearch.cpp index 1395bc8d2..0d3b226f0 100644 --- a/src/tools/codeeditor/uitreeviewglobalsearch.cpp +++ b/src/tools/codeeditor/uitreeviewglobalsearch.cpp @@ -43,7 +43,15 @@ UIPushButton* UITreeViewCellGlobalSearch::updateText( const std::string& text ) mTextBox->setFontFillColor( pp->getLineNumColor(), from, to ); } - mSearchStrPos = { text.find( pp->getSearchStr() ), pp->getSearchStr().size() }; + ModelIndex curIndex = getCurIndex(); + ModelIndex index = pp->getModel()->index( + curIndex.row(), ProjectSearch::ResultModel::ColumnPosition, curIndex.parent() ); + Variant variant = pp->getModel()->data( index, Model::Role::Custom ); + Int64 iniPos = 0; + if ( variant.is( Variant::Type::Int64 ) ) + iniPos = variant.asInt64(); + String txt( text ); + mSearchStrPos = { txt.find( pp->getSearchStr(), iniPos ), pp->getSearchStr().size() }; auto tokens = SyntaxTokenizer::tokenize( styleDef, text, SYNTAX_TOKENIZER_STATE_NONE, to ).first;