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* );