diff --git a/include/eepp/window/window.hpp b/include/eepp/window/window.hpp index 1bc49231a..72449300b 100644 --- a/include/eepp/window/window.hpp +++ b/include/eepp/window/window.hpp @@ -29,6 +29,12 @@ enum WindowStyle { #endif }; +enum class WindowFlashOperation { + Cancel, + Briefly, + UntilFocused, +}; + enum class WindowBackend : Uint32 { SDL2, Default }; #ifndef EE_SCREEN_KEYBOARD_ENABLED @@ -195,6 +201,9 @@ class EE_API Window { /** This will attempt to raise the window */ virtual void raise(); + /** Request a window to demand attention from the user. */ + virtual void flash( WindowFlashOperation op ); + /** This will attempt to show the window */ virtual void show(); @@ -474,7 +483,7 @@ class EE_API Window { /** Shows a native message box. * @return True if message box was shown - */ + */ virtual bool showMessageBox( const MessageBoxType& type, const std::string& title, const std::string& message ); diff --git a/projects/linux/ee.files b/projects/linux/ee.files index 1da1fdb14..e981615d6 100644 --- a/projects/linux/ee.files +++ b/projects/linux/ee.files @@ -1185,6 +1185,7 @@ ../../src/tools/ecode/plugins/formatter/formatterplugin.hpp ../../src/tools/ecode/notificationcenter.cpp ../../src/tools/ecode/notificationcenter.hpp +../../src/tools/ecode/pathhelper.hpp ../../src/tools/ecode/plugins/linter/linterplugin.cpp ../../src/tools/ecode/plugins/linter/linterplugin.hpp ../../src/tools/ecode/plugins/lsp/lspclientplugin.cpp diff --git a/src/eepp/ui/abstract/uiabstracttableview.cpp b/src/eepp/ui/abstract/uiabstracttableview.cpp index ebb2a6308..006ed9011 100644 --- a/src/eepp/ui/abstract/uiabstracttableview.cpp +++ b/src/eepp/ui/abstract/uiabstracttableview.cpp @@ -76,10 +76,14 @@ size_t UIAbstractTableView::getItemCount() const { void UIAbstractTableView::onModelUpdate( unsigned flags ) { if ( !Engine::instance()->isMainThread() ) { - runOnMainThread( [&, flags] { - modelUpdate( flags ); - createOrUpdateColumns( true ); - } ); + static constexpr String::HashType tag = String::hash( "onModelUpdate" ); + removeActionsByTag( tag ); + runOnMainThread( + [&, flags] { + modelUpdate( flags ); + createOrUpdateColumns( true ); + }, + Time::Zero, tag ); } else { UIAbstractView::onModelUpdate( flags ); createOrUpdateColumns( true ); diff --git a/src/eepp/ui/abstract/uiabstractview.cpp b/src/eepp/ui/abstract/uiabstractview.cpp index 72e99c3fd..e51963d05 100644 --- a/src/eepp/ui/abstract/uiabstractview.cpp +++ b/src/eepp/ui/abstract/uiabstractview.cpp @@ -122,7 +122,9 @@ void UIAbstractView::modelUpdate( unsigned flags ) { void UIAbstractView::onModelUpdate( unsigned flags ) { if ( !Engine::instance()->isMainThread() ) { - runOnMainThread( [&, flags] { modelUpdate( flags ); } ); + static constexpr String::HashType tag = String::hash( "onModelUpdate" ); + removeActionsByTag( tag ); + runOnMainThread( [&, flags] { modelUpdate( flags ); }, Time::Zero, tag ); } else { modelUpdate( flags ); } diff --git a/src/eepp/ui/models/filesystemmodel.cpp b/src/eepp/ui/models/filesystemmodel.cpp index de741045d..947efc1ed 100644 --- a/src/eepp/ui/models/filesystemmodel.cpp +++ b/src/eepp/ui/models/filesystemmodel.cpp @@ -279,7 +279,7 @@ FileSystemModel::FileSystemModel( const std::string& rootPath, const FileSystemM mDisplayConfig( displayConfig ) { mRoot = std::make_unique( mRootPath, *this ); mInitOK = true; - onModelUpdate(); + invalidate(); } FileSystemModel::~FileSystemModel() { @@ -317,8 +317,7 @@ FileSystemModel::Node* FileSystemModel::getNodeFromPath( std::string path, bool if ( !folders.empty() ) { for ( size_t i = 0; i < folders.size(); i++ ) { auto& part = folders[i]; - if ( ( foundNode = curNode->findChildName( - part, *this, invalidateTree || i == folders.size() - 1 ) ) ) { + if ( ( foundNode = curNode->findChildName( part, *this, invalidateTree ) ) ) { curNode = foundNode; } else { return nullptr; @@ -336,12 +335,12 @@ void FileSystemModel::reload() { void FileSystemModel::refresh() { Lock l( resourceMutex() ); mRoot->refresh( *this ); - onModelUpdate(); + invalidate(); } void FileSystemModel::update() { mRoot = std::make_unique( mRootPath, *this ); - onModelUpdate(); + invalidate(); } const FileSystemModel::Node& FileSystemModel::node( const ModelIndex& index ) const { @@ -599,58 +598,58 @@ bool FileSystemModel::handleFileEventLocked( const FileEvent& event ) { : file.getDirectoryPath(), true, false ); - if ( parent ) { - auto* childNodeExists = - getNodeFromPath( file.getFilepath(), file.isDirectory(), false ); - if ( childNodeExists ) - return false; + if ( !parent ) + return false; - Node* childNode = parent->createChild( file.getFileName(), *this ); + auto* childNodeExists = + getNodeFromPath( file.getFilepath(), file.isDirectory(), false ); + if ( childNodeExists ) + return false; - if ( !childNode->getName().empty() ) { - size_t pos = getFileIndex( parent, file ); + Node* childNode = parent->createChild( file.getFileName(), *this ); - const auto& displayCfg = getDisplayConfig(); + if ( childNode->getName().empty() ) + return false; - if ( displayCfg.fileIsVisibleFn && - !displayCfg.fileIsVisibleFn( file.getFilepath() ) ) - return false; + size_t pos = getFileIndex( parent, file ); - if ( pos == INDEX_ALREADY_EXISTS ) - return false; + const auto& displayCfg = getDisplayConfig(); - beginInsertRows( parent->index( *this, 0 ), pos, pos ); + if ( displayCfg.fileIsVisibleFn && !displayCfg.fileIsVisibleFn( file.getFilepath() ) ) + return false; - if ( pos >= parent->mChildren.size() ) { - parent->mChildren.emplace_back( childNode ); - } else { - parent->mChildren.insert( parent->mChildren.begin() + pos, childNode ); - } + if ( pos == INDEX_ALREADY_EXISTS ) + return false; - endInsertRows(); + beginInsertRows( parent->index( *this, 0 ), pos, pos ); - forEachView( [&]( UIAbstractView* view ) { - std::vector newIndexes; - view->getSelection().forEachIndex( [&]( const ModelIndex& selectedIndex ) { - Node* curNode = static_cast( selectedIndex.internalData() ); - if ( curNode->getParent() == parent ) { - if ( selectedIndex.row() >= (Int64)pos ) { - newIndexes.emplace_back( this->index( - selectedIndex.row() + 1, selectedIndex.column(), - selectedIndex.parent() ) ); - } else { - newIndexes.emplace_back( selectedIndex ); - } - } else { - newIndexes.emplace_back( selectedIndex ); - } - } ); - view->getSelection().set( newIndexes, false ); - } ); - } else { - return false; - } + if ( pos >= parent->mChildren.size() ) { + parent->mChildren.emplace_back( childNode ); + } else { + parent->mChildren.insert( parent->mChildren.begin() + pos, childNode ); } + + endInsertRows(); + + forEachView( [&]( UIAbstractView* view ) { + std::vector newIndexes; + view->getSelection().forEachIndex( [&]( const ModelIndex& selectedIndex ) { + Node* curNode = static_cast( selectedIndex.internalData() ); + if ( curNode->getParent() == parent ) { + if ( selectedIndex.row() >= (Int64)pos ) { + newIndexes.emplace_back( this->index( selectedIndex.row() + 1, + selectedIndex.column(), + selectedIndex.parent() ) ); + } else { + newIndexes.emplace_back( selectedIndex ); + } + } else { + newIndexes.emplace_back( selectedIndex ); + } + } ); + view->getSelection().set( newIndexes, false ); + } ); + break; } case FileSystemEventType::Delete: { @@ -710,92 +709,91 @@ bool FileSystemModel::handleFileEventLocked( const FileEvent& event ) { case FileSystemEventType::Moved: { FileInfo file( event.directory + event.filename, false ); - if ( file.exists() ) { - auto* node = getNodeFromPath( event.directory + event.oldFilename, false, false ); - if ( node ) { - ModelIndex index = node->index( *this, 0 ); - if ( !index.isValid() ) - return false; + if ( !file.exists() ) + return false; - Node* parent = node->mParent; - if ( !parent ) - return false; - - if ( ( getMode() == Mode::DirectoriesOnly && !file.isDirectory() ) ) - return false; - - if ( !node->info().isHidden() && getDisplayConfig().ignoreHidden && - file.isHidden() ) { - return handleFileEventLocked( - { FileSystemEventType::Delete, event.directory, event.oldFilename } ); - } - - Node* childNode = parent->mChildren[index.row()]; - childNode->rename( file ); - parent->mChildren.erase( parent->mChildren.begin() + index.row() ); - - size_t pos = getFileIndex( node->getParent(), file ); - - // Don't add the file if already exists (if moved an old file to another old - // file) - if ( pos == INDEX_ALREADY_EXISTS ) { - eeDelete( childNode ); - return false; - } - - std::map> keptSelections; - std::map> prevSelections; - std::map> prevSelectionsModelIndex; - - forEachView( [&]( UIAbstractView* view ) { - view->getSelection().forEachIndex( [&]( const ModelIndex& selectedIndex ) { - Node* curNode = static_cast( selectedIndex.internalData() ); - if ( curNode->mParent == parent ) { - prevSelectionsModelIndex[view].emplace_back( selectedIndex ); - prevSelections[view].emplace_back( - ( curNode->getName() == event.oldFilename ) - ? event.filename - : curNode->getName() ); - } else { - keptSelections[view].emplace_back( selectedIndex ); - } - } ); - } ); - - beginMoveRows( index.parent(), index.row(), index.row(), index.parent(), pos ); - - if ( pos >= parent->mChildren.size() ) { - parent->mChildren.emplace_back( childNode ); - } else { - parent->mChildren.insert( parent->mChildren.begin() + pos, childNode ); - } - - endMoveRows(); - - forEachView( [&]( UIAbstractView* view ) { - std::vector names = prevSelections[view]; - std::vector newIndexes = keptSelections[view]; - int i = 0; - for ( const auto& name : names ) { - Int64 row = parent->findChildRowFromName( name, *this ); - if ( row >= 0 ) { - newIndexes.emplace_back( - this->index( row, prevSelectionsModelIndex[view][i].column(), - prevSelectionsModelIndex[view][i].parent() ) ); - } - ++i; - } - view->getSelection().set( newIndexes, false ); - } ); - } else { - return handleFileEventLocked( - { FileSystemEventType::Add, event.directory, event.filename } ); - } + auto* node = getNodeFromPath( event.directory + event.oldFilename, false, false ); + if ( !node ) { + return handleFileEventLocked( + { FileSystemEventType::Add, event.directory, event.filename } ); } + + ModelIndex index = node->index( *this, 0 ); + if ( !index.isValid() ) + return false; + + Node* parent = node->mParent; + if ( !parent ) + return false; + + if ( ( getMode() == Mode::DirectoriesOnly && !file.isDirectory() ) ) + return false; + + if ( !node->info().isHidden() && getDisplayConfig().ignoreHidden && file.isHidden() ) { + return handleFileEventLocked( + { FileSystemEventType::Delete, event.directory, event.oldFilename } ); + } + + Node* childNode = parent->mChildren[index.row()]; + childNode->rename( file ); + parent->mChildren.erase( parent->mChildren.begin() + index.row() ); + + size_t pos = getFileIndex( node->getParent(), file ); + + // Don't add the file if already exists (if moved an old file to another old + // file) + if ( pos == INDEX_ALREADY_EXISTS ) { + eeDelete( childNode ); + return false; + } + + std::map> keptSelections; + std::map> prevSelections; + std::map> prevSelectionsModelIndex; + + forEachView( [&]( UIAbstractView* view ) { + view->getSelection().forEachIndex( [&]( const ModelIndex& selectedIndex ) { + Node* curNode = static_cast( selectedIndex.internalData() ); + if ( curNode->mParent == parent ) { + prevSelectionsModelIndex[view].emplace_back( selectedIndex ); + prevSelections[view].emplace_back( + ( curNode->getName() == event.oldFilename ) ? event.filename + : curNode->getName() ); + } else { + keptSelections[view].emplace_back( selectedIndex ); + } + } ); + } ); + + beginMoveRows( index.parent(), index.row(), index.row(), index.parent(), pos ); + + if ( pos >= parent->mChildren.size() ) { + parent->mChildren.emplace_back( childNode ); + } else { + parent->mChildren.insert( parent->mChildren.begin() + pos, childNode ); + } + + endMoveRows(); + + forEachView( [&]( UIAbstractView* view ) { + std::vector names = prevSelections[view]; + std::vector newIndexes = keptSelections[view]; + int i = 0; + for ( const auto& name : names ) { + Int64 row = parent->findChildRowFromName( name, *this ); + if ( row >= 0 ) { + newIndexes.emplace_back( + this->index( row, prevSelectionsModelIndex[view][i].column(), + prevSelectionsModelIndex[view][i].parent() ) ); + } + ++i; + } + view->getSelection().set( newIndexes, false ); + } ); break; } case FileSystemEventType::Modified: { - break; + return false; } } @@ -814,7 +812,8 @@ bool FileSystemModel::handleFileEvent( const FileEvent& event ) { ret = handleFileEventLocked( event ); } - onModelUpdate( UpdateFlag::DontInvalidateIndexes ); + if ( ret ) + invalidate( UpdateFlag::DontInvalidateIndexes ); return ret; } diff --git a/src/eepp/window/backend/SDL2/windowsdl2.cpp b/src/eepp/window/backend/SDL2/windowsdl2.cpp index 2cfdab3cd..28aa08990 100644 --- a/src/eepp/window/backend/SDL2/windowsdl2.cpp +++ b/src/eepp/window/backend/SDL2/windowsdl2.cpp @@ -785,6 +785,15 @@ void WindowSDL::raise() { SDL_RaiseWindow( mSDLWindow ); } +void WindowSDL::flash( WindowFlashOperation op ) { + SDL_FlashOperation sdlOp = SDL_FlashOperation::SDL_FLASH_BRIEFLY; + if ( op == WindowFlashOperation::Cancel ) + sdlOp = SDL_FlashOperation::SDL_FLASH_CANCEL; + else if ( op == WindowFlashOperation::UntilFocused ) + sdlOp = SDL_FlashOperation::SDL_FLASH_UNTIL_FOCUSED; + SDL_FlashWindow( mSDLWindow, sdlOp ); +} + void WindowSDL::show() { SDL_ShowWindow( mSDLWindow ); } diff --git a/src/eepp/window/backend/SDL2/windowsdl2.hpp b/src/eepp/window/backend/SDL2/windowsdl2.hpp index 12e77dd60..5f97d72ff 100644 --- a/src/eepp/window/backend/SDL2/windowsdl2.hpp +++ b/src/eepp/window/backend/SDL2/windowsdl2.hpp @@ -67,6 +67,8 @@ class EE_API WindowSDL : public Window { virtual void raise(); + virtual void flash( WindowFlashOperation op ); + virtual void show(); virtual void setPosition( int Left, int Top ); diff --git a/src/eepp/window/window.cpp b/src/eepp/window/window.cpp index 58727e5bd..3484cb503 100644 --- a/src/eepp/window/window.cpp +++ b/src/eepp/window/window.cpp @@ -517,6 +517,8 @@ void Window::hide() {} void Window::raise() {} +void Window::flash( WindowFlashOperation ) {} + void Window::show() {} void Window::setPosition( int, int ) {} diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index e9f0a9a34..2f5859876 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -1,5 +1,6 @@ #include "ecode.hpp" #include "featureshealth.hpp" +#include "pathhelper.hpp" #include "plugins/autocomplete/autocompleteplugin.hpp" #include "plugins/formatter/formatterplugin.hpp" #include "plugins/linter/linterplugin.hpp" @@ -32,48 +33,6 @@ bool firstFrame = true; bool firstUpdate = true; App* appInstance = nullptr; -static bool pathHasPosition( const std::string& path ) { -#if EE_PLATFORM == EE_PLATFORM_WIN - bool countedSep = std::count( path.begin(), path.end(), ':' ) > 1; -#else - bool countedSep = std::count( path.begin(), path.end(), ':' ) > 0; -#endif - if ( countedSep ) { - auto seps = String::split( path, ':' ); - return String::isNumber( seps.back() ); - } - return false; -} - -static std::pair getPathAndPosition( const std::string& path ) { - if ( pathHasPosition( path ) ) { - auto parts = String::split( path, ':' ); - if ( parts.size() >= 2 ) { - Int64 line = 0; - Int64 col = 0; -#if EE_PLATFORM == EE_PLATFORM_WIN - size_t partCount = 4; -#else - size_t partCount = 3; -#endif - int linePos = parts.size() >= partCount ? parts.size() - 2 : parts.size() - 1; - int colPos = parts.size() >= partCount ? parts.size() - 1 : -1; - if ( String::fromString( line, parts[linePos] ) ) { - if ( colPos > 0 ) - String::fromString( col, parts[colPos] ); - } - std::string npath( parts[0] ); - if ( parts.size() >= 2 ) { - for ( Int64 i = 1; i < linePos; i++ ) { - npath += ":" + parts[i]; - } - } - return { npath, { eemax( (Int64)0, line - 1 ), col } }; - } - } - return { path, { 0, 0 } }; -} - void appLoop() { appInstance->mainLoop(); } diff --git a/src/tools/ecode/pathhelper.hpp b/src/tools/ecode/pathhelper.hpp new file mode 100644 index 000000000..206d353a9 --- /dev/null +++ b/src/tools/ecode/pathhelper.hpp @@ -0,0 +1,56 @@ +#ifndef ECODE_PATHHELPER_HPP +#define ECODE_PATHHELPER_HPP + +#include +#include + +using namespace EE; +using namespace EE::UI::Doc; + +namespace ecode { + +template static bool pathHasPosition( const T& path ) { +#if EE_PLATFORM == EE_PLATFORM_WIN + bool countedSep = std::count( path.begin(), path.end(), ':' ) > 1; +#else + bool countedSep = std::count( path.begin(), path.end(), ':' ) > 0; +#endif + if ( countedSep ) { + auto seps = String::split( path, ':' ); + return String::isNumber( seps.back() ); + } + return false; +} + +template static std::pair getPathAndPosition( const T& path ) { + if ( pathHasPosition( path ) ) { + auto parts = String::split( path, ':' ); + if ( parts.size() >= 2 ) { + Int64 line = 0; + Int64 col = 0; +#if EE_PLATFORM == EE_PLATFORM_WIN + size_t partCount = 4; +#else + size_t partCount = 3; +#endif + int linePos = parts.size() >= partCount ? parts.size() - 2 : parts.size() - 1; + int colPos = parts.size() >= partCount ? parts.size() - 1 : -1; + if ( String::fromString( line, parts[linePos] ) ) { + if ( colPos > 0 ) + String::fromString( col, parts[colPos] ); + } + std::string npath( parts[0] ); + if ( parts.size() >= 2 ) { + for ( Int64 i = 1; i < linePos; i++ ) { + npath += ":" + parts[i]; + } + } + return { npath, { eemax( (Int64)0, line - 1 ), col } }; + } + } + return { path, { 0, 0 } }; +} + +} // namespace ecode + +#endif // ECODE_PATHHELPER_HPP diff --git a/src/tools/ecode/statusbuildoutputcontroller.cpp b/src/tools/ecode/statusbuildoutputcontroller.cpp index 883458844..6573746f4 100644 --- a/src/tools/ecode/statusbuildoutputcontroller.cpp +++ b/src/tools/ecode/statusbuildoutputcontroller.cpp @@ -257,6 +257,9 @@ void StatusBuildOutputController::runBuild( const std::string& buildName, if ( cleanButton ) cleanButton->setEnabled( true ); } + + if ( !mApp->getWindow()->hasFocus() ) + mApp->getWindow()->flash( WindowFlashOperation::Briefly ); } ); if ( !res.isValid() ) { @@ -344,6 +347,9 @@ void StatusBuildOutputController::runClean( const std::string& buildName, if ( buildButton ) buildButton->setEnabled( true ); } + + if ( !mApp->getWindow()->hasFocus() ) + mApp->getWindow()->flash( WindowFlashOperation::Briefly ); } ); if ( !res.isValid() ) { diff --git a/src/tools/ecode/universallocator.cpp b/src/tools/ecode/universallocator.cpp index 23916281c..648aa4575 100644 --- a/src/tools/ecode/universallocator.cpp +++ b/src/tools/ecode/universallocator.cpp @@ -1,5 +1,6 @@ #include "universallocator.hpp" #include "ecode.hpp" +#include "pathhelper.hpp" #include namespace ecode { @@ -136,22 +137,28 @@ void UniversalLocator::toggleLocateBar() { } void UniversalLocator::updateFilesTable() { + auto text = mLocateInput->getText(); + + if ( pathHasPosition( text ) ) { + auto pathAndPos = getPathAndPosition( text ); + text = pathAndPos.first; + } + if ( !mApp->isDirTreeReady() ) { mLocateTable->setModel( ProjectDirectoryTree::emptyModel( getLocatorCommands() ) ); mLocateTable->getSelection().set( mLocateTable->getModel()->index( 0 ) ); } else if ( !mLocateInput->getText().empty() ) { #if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN || defined( __EMSCRIPTEN_PTHREADS__ ) mApp->getDirTree()->asyncFuzzyMatchTree( - mLocateInput->getText(), LOCATEBAR_MAX_RESULTS, [&]( auto res ) { - mUISceneNode->runOnMainThread( [&, res] { + text, LOCATEBAR_MAX_RESULTS, [this, text]( auto res ) { + mUISceneNode->runOnMainThread( [this, res] { mLocateTable->setModel( res ); mLocateTable->getSelection().set( mLocateTable->getModel()->index( 0 ) ); mLocateTable->scrollToTop(); } ); } ); #else - mLocateTable->setModel( - mApp->getDirTree()->fuzzyMatchTree( mLocateInput->getText(), LOCATEBAR_MAX_RESULTS ) ); + mLocateTable->setModel( mApp->getDirTree()->fuzzyMatchTree( text, LOCATEBAR_MAX_RESULTS ) ); mLocateTable->getSelection().set( mLocateTable->getModel()->index( 0 ) ); mLocateTable->scrollToTop(); #endif @@ -335,22 +342,13 @@ void UniversalLocator::initLocateBar( UILocateBar* locateBar, UITextInput* locat auto range = rangeStr.isValid() ? TextRange::fromString( rangeStr.asStdString() ) : TextRange(); - UITab* tab = mSplitter->isDocumentOpen( path, true ); - if ( !tab ) { - FileInfo fileInfo( path ); - if ( fileInfo.exists() && fileInfo.isRegularFile() ) - mApp->loadFileFromPath( path, true, nullptr, - [range]( UICodeEditor* editor, auto ) { - if ( range.isValid() ) - editor->goToLine( range.start() ); - } ); - } else { - tab->getTabWidget()->setTabSelected( tab ); - if ( range.isValid() ) { - UICodeEditor* editor = tab->getOwnedWidget()->asType(); - editor->goToLine( range.start() ); - } + if ( !range.isValid() && !FileSystem::isRelativePath( path ) && + pathHasPosition( mLocateInput->getText() ) && + String::startsWith( mLocateInput->getText().toUtf8(), path ) ) { + auto pathAndPos = getPathAndPosition( mLocateInput->getText() ); + range = { pathAndPos.second, pathAndPos.second }; } + focusOrLoadFile( path, range ); mLocateBarLayout->execute( "close-locatebar" ); } else { Variant rangeStr( modelEvent->getModel()->data( @@ -525,6 +523,24 @@ std::shared_ptr UniversalLocator::openDocumentsModel( const std:: return std::make_shared( ffiles, fnames ); } +void UniversalLocator::focusOrLoadFile( const std::string& path, const TextRange& range ) { + UITab* tab = mSplitter->isDocumentOpen( path, true ); + if ( !tab ) { + FileInfo fileInfo( path ); + if ( fileInfo.exists() && fileInfo.isRegularFile() ) + mApp->loadFileFromPath( path, true, nullptr, [range]( UICodeEditor* editor, auto ) { + if ( range.isValid() ) + editor->goToLine( range.start() ); + } ); + } else { + tab->getTabWidget()->setTabSelected( tab ); + if ( range.isValid() ) { + UICodeEditor* editor = tab->getOwnedWidget()->asType(); + editor->goToLine( range.start() ); + } + } +} + void UniversalLocator::updateOpenDocumentsTable() { mLocateTable->setModel( openDocumentsModel( mLocateInput->getText().substr( 2 ).trim().toUtf8() ) ); diff --git a/src/tools/ecode/universallocator.hpp b/src/tools/ecode/universallocator.hpp index a42fd70ef..299c5415c 100644 --- a/src/tools/ecode/universallocator.hpp +++ b/src/tools/ecode/universallocator.hpp @@ -86,6 +86,8 @@ class UniversalLocator { void updateOpenDocumentsTable(); std::shared_ptr openDocumentsModel( const std::string& match ); + + void focusOrLoadFile( const std::string& path, const TextRange& range = {} ); }; } // namespace ecode