diff --git a/projects/linux/ee.files b/projects/linux/ee.files index 40b40a94e..1112374b0 100644 --- a/projects/linux/ee.files +++ b/projects/linux/ee.files @@ -1153,8 +1153,6 @@ ../../src/tools/ecode/docsearchcontroller.hpp ../../src/tools/ecode/featureshealth.cpp ../../src/tools/ecode/featureshealth.hpp -../../src/tools/ecode/filelocator.cpp -../../src/tools/ecode/filelocator.hpp ../../src/tools/ecode/filesystemlistener.cpp ../../src/tools/ecode/filesystemlistener.hpp ../../src/tools/ecode/globalsearchcontroller.cpp @@ -1196,6 +1194,8 @@ ../../src/tools/ecode/uicodeeditorsplitter.hpp ../../src/tools/ecode/uitreeviewglobalsearch.cpp ../../src/tools/ecode/uitreeviewglobalsearch.hpp +../../src/tools/ecode/universallocator.cpp +../../src/tools/ecode/universallocator.hpp ../../src/tools/ecode/version.cpp ../../src/tools/ecode/version.hpp ../../src/tools/ecode/widgetcommandexecuter.hpp diff --git a/src/eepp/ui/uitextinput.cpp b/src/eepp/ui/uitextinput.cpp index ce640bdd7..8dc87091c 100644 --- a/src/eepp/ui/uitextinput.cpp +++ b/src/eepp/ui/uitextinput.cpp @@ -706,6 +706,7 @@ void UITextInput::paste() { String::replaceAll( pasted, "\n", "" ); } mDoc.textInput( pasted ); + onTextChanged(); sendCommonEvent( Event::OnTextPasted ); } diff --git a/src/tools/ecode/commandpalette.hpp b/src/tools/ecode/commandpalette.hpp index d4a54b922..62d080c52 100644 --- a/src/tools/ecode/commandpalette.hpp +++ b/src/tools/ecode/commandpalette.hpp @@ -17,7 +17,7 @@ using CommandPaletteModel = ItemVectorListOwnerModel; class CommandPalette { public: - CommandPalette( const std::shared_ptr& pool ); + explicit CommandPalette( const std::shared_ptr& pool ); typedef std::function )> MatchResultCb; diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 63fc8077c..cc0951c62 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -1797,7 +1797,7 @@ void App::hideSearchBar() { } void App::hideLocateBar() { - mFileLocator->hideLocateBar(); + mUniversalLocator->hideLocateBar(); } bool App::isDirTreeReady() const { @@ -1898,7 +1898,7 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) { mSettings->updateDocumentMenu(); } } ); - doc.setCommand( "go-to-line", [&] { mFileLocator->goToLine(); } ); + doc.setCommand( "go-to-line", [&] { mUniversalLocator->goToLine(); } ); doc.setCommand( "load-current-dir", [&] { loadCurrentDirectory(); } ); registerUnlockedCommands( doc ); @@ -2073,7 +2073,7 @@ void App::loadDirTree( const std::string& path ) { eeDelete( clock ); mDirTreeReady = true; mUISceneNode->runOnMainThread( [&] { - mFileLocator->updateFilesTable(); + mUniversalLocator->updateFilesTable(); if ( mSplitter->curEditorExistsAndFocused() ) syncProjectTreeWithEditor( mSplitter->getCurEditor() ); } ); @@ -3123,7 +3123,7 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe { "symbol-boolean", 0xea8f }, { "symbol-array", 0xea8a }, { "symbol-object", 0xea8b }, { "symbol-key", 0xea93 }, { "symbol-null", 0xea8f }, { "collapse-all", 0xeac5 }, - }; + { "chevron-right", 0xeab6 } }; for ( const auto& icon : codIcons ) iconTheme->add( UIGlyphIcon::New( icon.first, codIconFont, icon.second ) ); @@ -3209,9 +3209,9 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe mUISceneNode->find( "global_search_bar" ), mConfig.globalSearchBarConfig, mGlobalSearchKeybindings ); - mFileLocator = std::make_unique( mSplitter, mUISceneNode, this ); - mFileLocator->initLocateBar( mUISceneNode->find( "locate_bar" ), - mUISceneNode->find( "locate_find" ) ); + mUniversalLocator = std::make_unique( mSplitter, mUISceneNode, this ); + mUniversalLocator->initLocateBar( mUISceneNode->find( "locate_bar" ), + mUISceneNode->find( "locate_find" ) ); initImageView(); diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index 5becf6060..05f1c2351 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -4,13 +4,13 @@ #include "appconfig.hpp" #include "docsearchcontroller.hpp" #include "featureshealth.hpp" -#include "filelocator.hpp" #include "filesystemlistener.hpp" #include "globalsearchcontroller.hpp" #include "notificationcenter.hpp" #include "plugins/pluginmanager.hpp" #include "projectdirectorytree.hpp" #include "terminalmanager.hpp" +#include "universallocator.hpp" #include #include #include @@ -135,7 +135,7 @@ class App : public UICodeEditorSplitter::Client { void panelPosition( const PanelPosition& panelPosition ); - FileLocator* getFileLocator() const { return mFileLocator.get(); } + UniversalLocator* getUniversalLocator() const { return mUniversalLocator.get(); } TerminalManager* getTerminalManager() const { return mTerminalManager.get(); } @@ -214,8 +214,8 @@ class App : public UICodeEditorSplitter::Client { t.setCommand( "console-toggle", [&] { consoleToggle(); } ); t.setCommand( "find-replace", [&] { showFindView(); } ); t.setCommand( "open-global-search", [&] { showGlobalSearch( false ); } ); - t.setCommand( "open-locatebar", [&] { mFileLocator->showLocateBar(); } ); - t.setCommand( "open-command-palette", [&] { mFileLocator->showCommandPalette(); } ); + t.setCommand( "open-locatebar", [&] { mUniversalLocator->showLocateBar(); } ); + t.setCommand( "open-command-palette", [&] { mUniversalLocator->showCommandPalette(); } ); t.setCommand( "editor-set-line-breaking-column", [&] { setLineBreakingColumn(); } ); t.setCommand( "editor-set-line-spacing", [&] { setLineSpacing(); } ); t.setCommand( "editor-set-cursor-blinking-time", [&] { setCursorBlinkingTime(); } ); @@ -370,7 +370,7 @@ class App : public UICodeEditorSplitter::Client { std::unordered_map mFilesFolderWatches; std::unique_ptr mGlobalSearchController; std::unique_ptr mDocSearchController; - std::unique_ptr mFileLocator; + std::unique_ptr mUniversalLocator; std::unique_ptr mNotificationCenter; std::string mLastFileFolder; ColorSchemePreference mUIColorScheme; diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp index c1928f029..b4b9cbf03 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -252,7 +252,9 @@ PluginRequestHandle LSPClientPlugin::processWorkspaceSymbol( const PluginMessage if ( !msg.isRequest() || !msg.isJSON() ) return {}; - auto servers = mClientManager.getAllRunningServers(); + auto servers = mClientManager.getFilteredServers( []( LSPClientServer* server ) { + return server->getCapabilities().workspaceSymbolProvider; + } ); if ( servers.empty() ) return {}; diff --git a/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp b/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp index ef00e1c67..ca9962daa 100644 --- a/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp @@ -461,4 +461,15 @@ std::vector LSPClientServerManager::getAllRunningServers() { return servers; } +std::vector LSPClientServerManager::getFilteredServers( + const std::function& filter ) { + std::vector servers; + Lock l( mClientsMutex ); + for ( auto& server : mClients ) { + if ( server.second->isRunning() && filter( server.second.get() ) ) + servers.push_back( server.second.get() ); + } + return servers; +} + } // namespace ecode diff --git a/src/tools/ecode/plugins/lsp/lspclientservermanager.hpp b/src/tools/ecode/plugins/lsp/lspclientservermanager.hpp index 68324f194..1babff8e4 100644 --- a/src/tools/ecode/plugins/lsp/lspclientservermanager.hpp +++ b/src/tools/ecode/plugins/lsp/lspclientservermanager.hpp @@ -46,6 +46,9 @@ class LSPClientServerManager { std::vector getAllRunningServers(); + std::vector + getFilteredServers( const std::function& filter ); + LSPClientServer* getOneLSPClientServer( UICodeEditor* editor ); LSPClientServer* getOneLSPClientServer( const std::shared_ptr& doc ); diff --git a/src/tools/ecode/projectdirectorytree.cpp b/src/tools/ecode/projectdirectorytree.cpp index b385a59d7..aa396d73d 100644 --- a/src/tools/ecode/projectdirectorytree.cpp +++ b/src/tools/ecode/projectdirectorytree.cpp @@ -163,7 +163,9 @@ void ProjectDirectoryTree::asyncMatchTree( const std::string& match, const size_ mPool->run( [&, match, max, res]() { res( matchTree( match, max ) ); }, []() {} ); } -std::shared_ptr ProjectDirectoryTree::asModel( const size_t& max ) const { +std::shared_ptr +ProjectDirectoryTree::asModel( const size_t& max, + const std::vector& prependCommands ) const { if ( mNames.empty() ) return std::make_shared( std::vector(), std::vector() ); @@ -174,7 +176,22 @@ std::shared_ptr ProjectDirectoryTree::asModel( const size_t& max files[i] = mFiles[i]; names[i] = mNames[i]; } - return std::make_shared( files, names ); + if ( !prependCommands.empty() ) { + int count = 0; + for ( const auto& cmd : prependCommands ) { + names.insert( names.begin() + count, cmd.name ); + files.insert( files.begin() + count, cmd.desc ); + count++; + } + } + auto model = std::make_shared( files, names ); + + if ( !prependCommands.empty() ) { + for ( size_t i = 0; i < prependCommands.size(); ++i ) + model->setIcon( i, prependCommands[i].icon ); + } + + return model; } size_t ProjectDirectoryTree::getFilesCount() const { diff --git a/src/tools/ecode/projectdirectorytree.hpp b/src/tools/ecode/projectdirectorytree.hpp index fa4a421ba..6d2ed91c2 100644 --- a/src/tools/ecode/projectdirectorytree.hpp +++ b/src/tools/ecode/projectdirectorytree.hpp @@ -55,6 +55,11 @@ class FileListModel : public Model { return {}; } + void setIcon( size_t idx, UIIcon* icon ) { + eeASSERT( idx < mIcons.size() ); + mIcons[idx] = icon; + } + virtual void update() { onModelUpdate(); } protected: @@ -116,7 +121,14 @@ class ProjectDirectoryTree { void asyncMatchTree( const std::string& match, const size_t& max, MatchResultCb res ) const; - std::shared_ptr asModel( const size_t& max ) const; + struct CommandInfo { + std::string name; + std::string desc; + UIIcon* icon{ nullptr }; + }; + + std::shared_ptr + asModel( const size_t& max, const std::vector& prependCommands = {} ) const; size_t getFilesCount() const; diff --git a/src/tools/ecode/filelocator.cpp b/src/tools/ecode/universallocator.cpp similarity index 83% rename from src/tools/ecode/filelocator.cpp rename to src/tools/ecode/universallocator.cpp index 9d510fcaa..e54c33096 100644 --- a/src/tools/ecode/filelocator.cpp +++ b/src/tools/ecode/universallocator.cpp @@ -1,4 +1,4 @@ -#include "filelocator.hpp" +#include "universallocator.hpp" #include "ecode.hpp" namespace ecode { @@ -77,7 +77,8 @@ class LSPSymbolInfoModel : public Model { static int LOCATEBAR_MAX_VISIBLE_ITEMS = 18; static int LOCATEBAR_MAX_RESULTS = 100; -FileLocator::FileLocator( UICodeEditorSplitter* editorSplitter, UISceneNode* sceneNode, App* app ) : +UniversalLocator::UniversalLocator( UICodeEditorSplitter* editorSplitter, UISceneNode* sceneNode, + App* app ) : mSplitter( editorSplitter ), mUISceneNode( sceneNode ), mApp( app ), @@ -87,12 +88,12 @@ FileLocator::FileLocator( UICodeEditorSplitter* editorSplitter, UISceneNode* sce [&]( const PluginMessage& msg ) -> PluginRequestHandle { return processResponse( msg ); } ); } -void FileLocator::hideLocateBar() { +void UniversalLocator::hideLocateBar() { mLocateBarLayout->setVisible( false ); mLocateTable->setVisible( false ); } -void FileLocator::updateFilesTable() { +void UniversalLocator::updateFilesTable() { if ( !mLocateInput->getText().empty() ) { #if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN || defined( __EMSCRIPTEN_PTHREADS__ ) mApp->getDirTree()->asyncFuzzyMatchTree( @@ -110,12 +111,13 @@ void FileLocator::updateFilesTable() { mLocateTable->scrollToTop(); #endif } else { - mLocateTable->setModel( mApp->getDirTree()->asModel( LOCATEBAR_MAX_RESULTS ) ); + mLocateTable->setModel( + mApp->getDirTree()->asModel( LOCATEBAR_MAX_RESULTS, getLocatorCommands() ) ); mLocateTable->getSelection().set( mLocateTable->getModel()->index( 0 ) ); } } -void FileLocator::updateCommandPaletteTable() { +void UniversalLocator::updateCommandPaletteTable() { if ( !mCommandPalette.isSet() ) mCommandPalette.setCommandPalette( mApp->getMainLayout()->getCommandList(), mApp->getMainLayout()->getKeyBindings() ); @@ -154,19 +156,23 @@ void FileLocator::updateCommandPaletteTable() { mLocateTable->setColumnsVisible( { 0, 1 } ); } -void FileLocator::showLocateTable() { +void UniversalLocator::showLocateTable() { mLocateTable->setVisible( true ); Vector2f pos( mLocateInput->convertToWorldSpace( { 0, 0 } ) ); pos.y -= mLocateTable->getPixelsSize().getHeight(); mLocateTable->setPixelsPosition( pos ); } -void FileLocator::goToLine() { +void UniversalLocator::goToLine() { showLocateBar(); mLocateInput->setText( "l " ); } -void FileLocator::initLocateBar( UILocateBar* locateBar, UITextInput* locateInput ) { +static bool isCommand( const std::string& filename ) { + return !filename.empty() && ( filename == "> " || filename == ": " || filename == "l " ); +} + +void UniversalLocator::initLocateBar( UILocateBar* locateBar, UITextInput* locateInput ) { mLocateBarLayout = locateBar; mLocateInput = locateInput; auto addClickListener = [&]( UIWidget* widget, std::string cmd ) { @@ -243,12 +249,22 @@ void FileLocator::initLocateBar( UILocateBar* locateBar, UITextInput* locateInpu } hideLocateBar(); } else { + Variant vName( modelEvent->getModel()->data( + modelEvent->getModel()->index( modelEvent->getModelIndex().row(), 0 ), + ModelRole::Display ) ); + if ( isCommand( vName.toString() ) ) { + mLocateInput->setText( vName.toString() ); + return; + } Variant vPath( modelEvent->getModel()->data( modelEvent->getModel()->index( modelEvent->getModelIndex().row(), 1 ), ModelRole::Display ) ); if ( vPath.isValid() ) { std::string path( vPath.is( Variant::Type::cstr ) ? vPath.asCStr() : vPath.asStdString() ); + if ( path.empty() ) + return; + Variant rangeStr( modelEvent->getModel()->data( modelEvent->getModel()->index( modelEvent->getModelIndex().row(), 1 ), ModelRole::Custom ) ); @@ -278,7 +294,7 @@ void FileLocator::initLocateBar( UILocateBar* locateBar, UITextInput* locateInpu } ); } -void FileLocator::updateLocateBar() { +void UniversalLocator::updateLocateBar() { mLocateBarLayout->runOnMainThread( [&] { Float width = eeceil( mLocateInput->getPixelsSize().getWidth() ); mLocateTable->setPixelsSize( width, @@ -293,7 +309,7 @@ void FileLocator::updateLocateBar() { } ); } -void FileLocator::showBar() { +void UniversalLocator::showBar() { mApp->hideGlobalSearchBar(); mApp->hideSearchBar(); @@ -318,7 +334,7 @@ void FileLocator::showBar() { [&]( const Event* ) { updateLocateBar(); } ); } -void FileLocator::showLocateBar() { +void UniversalLocator::showLocateBar() { showBar(); if ( !mLocateInput->getText().empty() && @@ -326,14 +342,15 @@ void FileLocator::showLocateBar() { mLocateInput->setText( "" ); if ( mApp->getDirTree() && !mLocateTable->getModel() ) { - mLocateTable->setModel( mApp->getDirTree()->asModel( LOCATEBAR_MAX_RESULTS ) ); + mLocateTable->setModel( + mApp->getDirTree()->asModel( LOCATEBAR_MAX_RESULTS, getLocatorCommands() ) ); mLocateTable->getSelection().set( mLocateTable->getModel()->index( 0 ) ); } updateLocateBar(); } -void FileLocator::showCommandPalette() { +void UniversalLocator::showCommandPalette() { showBar(); if ( mLocateInput->getText().empty() || mLocateInput->getText()[0] != '>' ) @@ -343,7 +360,7 @@ void FileLocator::showCommandPalette() { updateLocateBar(); } -void FileLocator::showWorkspaceSymbol() { +void UniversalLocator::showWorkspaceSymbol() { showBar(); if ( mLocateInput->getText().empty() || mLocateInput->getText()[0] != ':' ) @@ -353,7 +370,7 @@ void FileLocator::showWorkspaceSymbol() { updateLocateBar(); } -void FileLocator::requestWorkspaceSymbol() { +void UniversalLocator::requestWorkspaceSymbol() { if ( mLocateInput->getText().empty() ) return; auto txt( mLocateInput->getText().substr( 1 ).trim() ); @@ -362,16 +379,22 @@ void FileLocator::requestWorkspaceSymbol() { if ( mWorkspaceSymbolModel ) { mWorkspaceSymbolModel->setQuery( mWorkspaceSymbolQuery ); } else { - mWorkspaceSymbolModel = - LSPSymbolInfoModel::create( mApp->getUISceneNode(), mWorkspaceSymbolQuery, {} ); + auto defTxt = mUISceneNode->i18n( "no_running_lsp_server", "No running LSP server" ); + LSPSymbolInformation info; + info.name = defTxt.toUtf8(); + info.url = ""; + mWorkspaceSymbolModel = LSPSymbolInfoModel::create( mApp->getUISceneNode(), + mWorkspaceSymbolQuery, { info } ); } + mLocateTable->setModel( mWorkspaceSymbolModel ); + json j = json{ json{ "query", mWorkspaceSymbolQuery } }; mApp->getPluginManager()->sendRequest( PluginMessageType::WorkspaceSymbol, PluginMessageFormat::JSON, &j ); } } -void FileLocator::updateWorkspaceSymbol( const std::vector& res ) { +void UniversalLocator::updateWorkspaceSymbol( const std::vector& res ) { #if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN || defined( __EMSCRIPTEN_PTHREADS__ ) mUISceneNode->runOnMainThread( [&, res] { if ( !mWorkspaceSymbolModel ) { @@ -391,7 +414,24 @@ void FileLocator::updateWorkspaceSymbol( const std::vector #endif } -PluginRequestHandle FileLocator::processResponse( const PluginMessage& msg ) { +std::vector UniversalLocator::getLocatorCommands() const { + std::vector vec; + UIIcon* icon = mUISceneNode->findIcon( "chevron-right" ); + vec.push_back( { "> ", + mUISceneNode->i18n( "search_in_command_palette", "Search in Command Palette" ), + icon } ); + vec.push_back( + { ": ", + mUISceneNode->i18n( "search_for_workspace_symbols", "Search for Workspace Symbols" ), + icon } ); + vec.push_back( + { "l ", + mUISceneNode->i18n( "go_to_line_in_current_document", "Go To Line in Current Document" ), + icon } ); + return vec; +} + +PluginRequestHandle UniversalLocator::processResponse( const PluginMessage& msg ) { if ( msg.isResponse() && msg.type == PluginMessageType::WorkspaceSymbol ) { updateWorkspaceSymbol( msg.asSymbolInformation() ); } diff --git a/src/tools/ecode/filelocator.hpp b/src/tools/ecode/universallocator.hpp similarity index 76% rename from src/tools/ecode/filelocator.hpp rename to src/tools/ecode/universallocator.hpp index 921e880e7..1db7e7031 100644 --- a/src/tools/ecode/filelocator.hpp +++ b/src/tools/ecode/universallocator.hpp @@ -1,8 +1,9 @@ -#ifndef ECODE_FILELOCATOR_HPP -#define ECODE_FILELOCATOR_HPP +#ifndef ECODE_UNIVERSALLOCATOR_HPP +#define ECODE_UNIVERSALLOCATOR_HPP #include "commandpalette.hpp" #include "plugins/pluginmanager.hpp" +#include "projectdirectorytree.hpp" #include "widgetcommandexecuter.hpp" #include @@ -11,9 +12,9 @@ namespace ecode { class App; class LSPSymbolInfoModel; -class FileLocator { +class UniversalLocator { public: - FileLocator( UICodeEditorSplitter* editorSplitter, UISceneNode* sceneNode, App* app ); + UniversalLocator( UICodeEditorSplitter* editorSplitter, UISceneNode* sceneNode, App* app ); void initLocateBar( UILocateBar* locateBar, UITextInput* locateInput ); @@ -53,8 +54,10 @@ class FileLocator { void requestWorkspaceSymbol(); void updateWorkspaceSymbol( const std::vector& info ); + + std::vector getLocatorCommands() const; }; } // namespace ecode -#endif // ECODE_FILELOCATOR_HPP +#endif // ECODE_UNIVERSALLOCATOR_HPP