From cac43d02762644e229ac00e5895415d6e0a79f13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Sun, 27 Oct 2024 21:46:24 -0300 Subject: [PATCH] Display subfolder hint/info when two or more files have the same file name but different paths. Fix an small bug where selection wasn't totally visible on lines bigger than the viewport and selection covering more than the whole viewport. --- .../eepp/ui/tools/uicodeeditorsplitter.hpp | 2 + src/eepp/ui/tools/uicodeeditorsplitter.cpp | 7 ++ src/eepp/ui/uicodeeditor.cpp | 6 +- src/tools/ecode/ecode.cpp | 106 +++++++++++++++++- src/tools/ecode/ecode.hpp | 2 + 5 files changed, 118 insertions(+), 5 deletions(-) diff --git a/include/eepp/ui/tools/uicodeeditorsplitter.hpp b/include/eepp/ui/tools/uicodeeditorsplitter.hpp index f847f27d4..c18decc36 100644 --- a/include/eepp/ui/tools/uicodeeditorsplitter.hpp +++ b/include/eepp/ui/tools/uicodeeditorsplitter.hpp @@ -180,6 +180,8 @@ class EE_API UICodeEditorSplitter { void forEachTabWidget( std::function run ) const; + void forEachTabWidgetStoppable( std::function run ) const; + void zoomIn(); void zoomOut(); diff --git a/src/eepp/ui/tools/uicodeeditorsplitter.cpp b/src/eepp/ui/tools/uicodeeditorsplitter.cpp index 1e83c9cb6..5f42e68c5 100644 --- a/src/eepp/ui/tools/uicodeeditorsplitter.cpp +++ b/src/eepp/ui/tools/uicodeeditorsplitter.cpp @@ -835,6 +835,13 @@ void UICodeEditorSplitter::forEachTabWidget( std::function run( widget ); } +void UICodeEditorSplitter::forEachTabWidgetStoppable( + std::function run ) const { + for ( auto widget : mTabWidgets ) + if ( run( widget ) ) + return; +} + void UICodeEditorSplitter::forEachEditorStoppable( std::function run ) const { for ( auto tabWidget : mTabWidgets ) { diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index f9164d465..439cbacb3 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -3726,6 +3726,8 @@ UICodeEditor::getTextRangeRectangles( const TextRange& range, const Vector2f& st ln == range.start().line() ? range.start() : mDoc->startOfLine( { ln, 0 } ) ); auto toInfo = mDocView.getVisibleLineRange( ln == range.end().line() ? range.end() : mDoc->endOfLine( { ln, 0 } ) ); + auto realFromInfoVisibleIndex = fromInfo.visibleIndex; + auto realToInfoVisibleIndex = toInfo.visibleIndex; if ( visibleLineRange ) { if ( fromInfo.visibleIndex < visibleLineRange->first ) fromInfo.visibleIndex = visibleLineRange->first; @@ -3740,7 +3742,7 @@ UICodeEditor::getTextRangeRectangles( const TextRange& range, const Vector2f& st Vector2d startOffset; Vector2d endOffset; if ( ln == range.start().line() && fromInfo.range.start().line() == ln && - fromInfo.visibleIndex == static_cast( visibleIdx ) ) { + realFromInfoVisibleIndex == static_cast( visibleIdx ) ) { startOffset = getTextPositionOffset( range.start(), lh ); } else { startOffset = getTextPositionOffset( info, lh ); @@ -3749,7 +3751,7 @@ UICodeEditor::getTextRangeRectangles( const TextRange& range, const Vector2f& st selRect.Bottom = selRect.Top + lh; selRect.Left = startScroll.x + startOffset.x; if ( ln == range.end().line() && toInfo.range.end().line() == ln && - toInfo.visibleIndex == static_cast( visibleIdx ) ) { + realToInfoVisibleIndex == static_cast( visibleIdx ) ) { endOffset = getTextPositionOffset( range.end(), lh ); } else { auto nextInfo = mDocView.getVisibleIndexPosition( diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index b5bd9df2f..6bdb19aec 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -50,6 +50,7 @@ bool firstUpdate = true; App* appInstance = nullptr; static const Uint32 APP_LAYOUT_STYLE_MARKER = String::hash( "app_layout_style" ); +static const auto NOT_UNIQUE_FILENAME = "not_unique"; void appLoop() { appInstance->mainLoop(); @@ -152,14 +153,108 @@ std::string App::titleFromEditor( UICodeEditor* editor ) { return editor->getDocument().isDirty() ? title + "*" : title; } +void App::updateNonUniqueTabTitles() { + if ( mSplitter == nullptr ) + return; + mSplitter->forEachEditor( [this]( UICodeEditor* editor ) { + if ( editor->hasClass( NOT_UNIQUE_FILENAME ) ) + updateEditorTabTitle( editor ); + } ); +} + void App::updateEditorTabTitle( UICodeEditor* editor ) { + const auto isUniqueTabTitle = [this]( UITab* tab ) -> bool { + bool unique = true; + auto doc = tab->getOwnedWidget()->asType()->getDocumentRef(); + auto fileName = doc->getFilename(); + mSplitter->forEachTabWidgetStoppable( [tab, &unique, &fileName, + &doc]( UITabWidget* tabWidget ) { + for ( size_t i = 0; i < tabWidget->getTabCount(); i++ ) { + UITab* curTab = tabWidget->getTab( i ); + if ( !curTab->getOwnedWidget()->isType( UI_TYPE_CODEEDITOR ) ) + continue; + auto curDoc = curTab->getOwnedWidget()->asType()->getDocumentRef(); + if ( curDoc && tab != curTab && fileName == curDoc->getFilename() && + doc->getFilePath() != curDoc->getFilePath() ) { + unique = false; + return true; + } + } + return false; + } ); + return unique; + }; + + const auto getTabWithSameTitle = [this]( UITab* tab ) -> std::vector { + std::vector tabs{ tab }; + auto doc = tab->getOwnedWidget()->asType()->getDocumentRef(); + const auto& fileName = doc->getFilename(); + mSplitter->forEachTabWidget( [tab, &tabs, &fileName]( UITabWidget* tabWidget ) { + for ( size_t i = 0; i < tabWidget->getTabCount(); i++ ) { + UITab* curTab = tabWidget->getTab( i ); + if ( !curTab->getOwnedWidget()->isType( UI_TYPE_CODEEDITOR ) ) + continue; + auto curDoc = curTab->getOwnedWidget()->asType()->getDocumentRef(); + if ( curDoc && tab != curTab && fileName == curDoc->getFilename() ) + tabs.push_back( curTab ); + } + } ); + return tabs; + }; + + const auto getUniqueNameForTabs = + []( const std::vector& tabs ) -> std::unordered_map { + std::unordered_map uniqueTitles; + + size_t subFoldersDisplayed = 1; + String firstTitle; + do { + for ( UITab* tab : tabs ) { + auto doc = tab->getOwnedWidget()->asType()->getDocumentRef(); + auto path = doc->getFilePath(); + std::string fileName = FileSystem::fileNameFromPath( path ); + std::string containingFolder = FileSystem::fileRemoveFileName( path ); + std::vector displayedFolders; + + for ( size_t i = 0; i < subFoldersDisplayed; i++ ) { + FileSystem::dirRemoveSlashAtEnd( containingFolder ); + displayedFolders.insert( displayedFolders.begin(), + FileSystem::fileNameFromPath( containingFolder ) ); + containingFolder = FileSystem::fileRemoveFileName( containingFolder ); + } + + uniqueTitles[tab] = fileName + " - " + String::join( displayedFolders, '/' ); + } + + subFoldersDisplayed++; + firstTitle = uniqueTitles.begin()->second; + } while ( std::all_of( ++uniqueTitles.begin(), uniqueTitles.end(), + [&firstTitle]( const std::pair& title ) { + return title.second == firstTitle; + } ) ); + + return uniqueTitles; + }; + if ( editor == nullptr ) return; if ( editor->getData() ) { UITab* tab = (UITab*)editor->getData(); - tab->setText( editor->getDocument().getFilename() ); + auto doc = editor->getDocumentRef(); + tab->setText( doc->getFilename() ); - bool dirty = editor->getDocument().isDirty(); + if ( tab->getText() != doc->getDefaultFileName() && !isUniqueTabTitle( tab ) ) { + auto tabsTitles = getUniqueNameForTabs( getTabWithSameTitle( tab ) ); + for ( auto [ntab, title] : tabsTitles ) { + ntab->setText( title ); + if ( ntab->getOwnedWidget()->isType( UI_TYPE_CODEEDITOR ) ) + ntab->getOwnedWidget()->asType()->addClass( NOT_UNIQUE_FILENAME ); + } + } else if ( tab->getOwnedWidget()->isType( UI_TYPE_CODEEDITOR ) ) { + tab->getOwnedWidget()->asType()->removeClass( NOT_UNIQUE_FILENAME ); + } + + bool dirty = doc->isDirty(); tab->removeClass( dirty ? "tab_clear" : "tab_modified" ); tab->addClass( dirty ? "tab_modified" : "tab_clear" ); } @@ -2246,7 +2341,7 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) { return; std::string processPath = Sys::getProcessFilePath(); if ( !processPath.empty() ) { - std::string cmd( processPath + " -x \"" + editor->getDocumentRef()->getFilePath() + "\"" ); + auto cmd( processPath + " -x \"" + editor->getDocumentRef()->getFilePath() + "\"" ); Sys::execute( cmd ); } } ); @@ -2291,6 +2386,11 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) { editor->getKeyBindings().addKeybindsStringUnordered( mKeybindings ); } + editor->on( Event::OnClose, [this, editor]( auto ) { + if ( editor->hasClass( NOT_UNIQUE_FILENAME ) ) + updateNonUniqueTabTitles(); + } ); + editor->on( Event::OnDocumentClosed, [this]( const Event* event ) { if ( !appInstance ) return; diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index 6d246a3b8..b3201b68c 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -580,6 +580,8 @@ class App : public UICodeEditorSplitter::Client { void updateEditorTabTitle( UICodeEditor* editor ); + void updateNonUniqueTabTitles(); + std::string titleFromEditor( UICodeEditor* editor ); bool onCloseRequestCallback( EE::Window::Window* );