diff --git a/include/eepp/core/string.hpp b/include/eepp/core/string.hpp index 1b01870a5..f28fa5593 100644 --- a/include/eepp/core/string.hpp +++ b/include/eepp/core/string.hpp @@ -832,6 +832,12 @@ class EE_API String { /** Replace all occurrences of the search string with the replacement string. */ void replaceAll( const String& that, const String& with ); + void pop_back(); + + const StringBaseType& front() const; + + const StringBaseType& back() const; + private: friend EE_API bool operator==( const String& left, const String& right ); friend EE_API bool operator<( const String& left, const String& right ); diff --git a/src/eepp/core/string.cpp b/src/eepp/core/string.cpp index df8d7ce35..9aad8ea89 100644 --- a/src/eepp/core/string.cpp +++ b/src/eepp/core/string.cpp @@ -711,6 +711,18 @@ void String::replaceAll( const String& that, const String& with ) { String::replaceAll( *this, that, with ); } +void String::pop_back() { + mString.pop_back(); +} + +const String::StringBaseType& String::front() const { + return mString.front(); +} + +const String::StringBaseType& String::back() const { + return mString.back(); +} + void String::replace( std::string& target, const std::string& that, const std::string& with ) { std::size_t start_pos = target.find( that ); if ( start_pos == std::string::npos ) diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index 7538539a9..bc6e90359 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -1012,16 +1012,19 @@ bool UICodeEditor::onCreateContextMenu( const Vector2i& position, const Uint32& } ); Vector2f pos( position.asFloat() ); - menu->nodeToWorldTranslation( pos ); - UIMenu::findBestMenuPos( pos, menu ); - menu->setPixelsPosition( pos ); - menu->show(); + runOnMainThread( [this, menu, pos]() { + Vector2f npos( pos ); + menu->nodeToWorldTranslation( npos ); + UIMenu::findBestMenuPos( npos, menu ); + menu->setPixelsPosition( npos ); + menu->show(); + mCurrentMenu = menu; + } ); menu->addEventListener( Event::OnMenuHide, [&]( const Event* ) { if ( !isClosing() ) setFocus(); } ); menu->addEventListener( Event::OnClose, [&]( const Event* ) { mCurrentMenu = nullptr; } ); - mCurrentMenu = menu; return true; } @@ -1111,6 +1114,8 @@ Uint32 UICodeEditor::onMouseDown( const Vector2i& position, const Uint32& flags } else { mDoc->setSelection( resolveScreenPosition( position.asFloat() ) ); } + } else { + mDoc->setSelection( resolveScreenPosition( position.asFloat() ) ); } } return UIWidget::onMouseDown( position, flags ); diff --git a/src/tools/ecode/globalsearchcontroller.cpp b/src/tools/ecode/globalsearchcontroller.cpp index 6fa4b105d..be3d0c5d7 100644 --- a/src/tools/ecode/globalsearchcontroller.cpp +++ b/src/tools/ecode/globalsearchcontroller.cpp @@ -7,7 +7,11 @@ static int LOCATEBAR_MAX_VISIBLE_ITEMS = 18; GlobalSearchController::GlobalSearchController( UICodeEditorSplitter* editorSplitter, UISceneNode* sceneNode, App* app ) : - mEditorSplitter( editorSplitter ), mUISceneNode( sceneNode ), mApp( app ) {} + mSplitter( editorSplitter ), mUISceneNode( sceneNode ), mApp( app ) { + mApp->getPluginManager()->subscribeMessages( + "GlobalSearchController", + [&]( const PluginMessage& msg ) -> PluginRequestHandle { return processMessage( msg ); } ); +} static bool replaceInFile( const std::string& path, const std::string& replaceText, const std::vector>& replacements ) { @@ -30,8 +34,13 @@ static bool replaceInFile( const std::string& path, const std::string& replaceTe size_t GlobalSearchController::replaceInFiles( const std::string& replaceText, std::shared_ptr model ) { - const ProjectSearch::Result& res = model.get()->getResult(); size_t count = 0; + if ( model->isResultFromSymbolReference() ) { + // TODO Implement replacement from result from symbol reference + return count; + } + + const ProjectSearch::Result& res = model.get()->getResult(); for ( const auto& fileResult : res ) { std::vector> replacements; @@ -133,8 +142,8 @@ void GlobalSearchController::initGlobalSearchBar( } ); mGlobalSearchBarLayout->setCommand( "close-global-searchbar", [&] { hideGlobalSearchBar(); - if ( mEditorSplitter->getCurWidget() ) - mEditorSplitter->getCurWidget()->setFocus(); + if ( mSplitter->getCurWidget() ) + mSplitter->getCurWidget()->setFocus(); } ); mGlobalSearchBarLayout->setCommand( "expand-all", [&] { mGlobalSearchTree->expandAll(); @@ -250,9 +259,18 @@ void GlobalSearchController::initGlobalSearchBar( replaceInput->getDocument().selectAll(); return; } - doGlobalSearch( mGlobalSearchInput->getText(), caseSensitiveChk->isChecked(), - wholeWordChk->isChecked(), luaPatternChk->isChecked(), - escapeSequenceChk->isChecked(), true ); + + // TODO Implement replacement from result from symbol reference + /*if ( mGlobalSearchHistory.back().second->isResultFromSymbolReference() ) { + mGlobalSearchTreeReplace->setModel( mGlobalSearchHistory.back().second ); + showGlobalSearch( true ); + updateGlobalSearchBarResults( mGlobalSearchHistory.back().first, + mGlobalSearchHistory.back().second, true, false ); + } else*/ { + doGlobalSearch( mGlobalSearchInput->getText(), caseSensitiveChk->isChecked(), + wholeWordChk->isChecked(), luaPatternChk->isChecked(), + escapeSequenceChk->isChecked(), true ); + } } ); mGlobalSearchBarLayout->setCommand( "replace-in-files", [&, replaceInput, escapeSequenceChk] { auto listBox = mGlobalSearchHistoryList->getListBox(); @@ -270,9 +288,9 @@ void GlobalSearchController::initGlobalSearchBar( } } ); mGlobalSearchTreeSearch = - UITreeViewGlobalSearch::New( mEditorSplitter->getCurrentColorScheme(), false ); + UITreeViewGlobalSearch::New( mSplitter->getCurrentColorScheme(), false ); mGlobalSearchTreeReplace = - UITreeViewGlobalSearch::New( mEditorSplitter->getCurrentColorScheme(), true ); + UITreeViewGlobalSearch::New( mSplitter->getCurrentColorScheme(), true ); initGlobalSearchTree( mGlobalSearchTreeSearch ); initGlobalSearchTree( mGlobalSearchTreeReplace ); mGlobalSearchTreeReplace->addEventListener( Event::KeyDown, [&]( const Event* event ) { @@ -295,9 +313,9 @@ void GlobalSearchController::showGlobalSearch( bool searchReplace ) { mGlobalSearchInput->setFocus(); mGlobalSearchLayout->setVisible( true ); UICheckBox* escapeSequenceChk = mGlobalSearchBarLayout->find( "escape_sequence" ); - if ( mEditorSplitter->curEditorExistsAndFocused() && - mEditorSplitter->getCurEditor()->getDocument().hasSelection() ) { - auto& doc = mEditorSplitter->getCurEditor()->getDocument(); + if ( mSplitter->curEditorExistsAndFocused() && + mSplitter->getCurEditor()->getDocument().hasSelection() ) { + auto& doc = mSplitter->getCurEditor()->getDocument(); String text = doc.getSelectedText(); if ( !doc.getSelection().inSameLine() ) { text.escape(); @@ -405,6 +423,40 @@ void GlobalSearchController::updateGlobalSearchBarResults( } } +void GlobalSearchController::updateGlobalSearchHistory( + std::shared_ptr model, const std::string& search, + bool searchReplace, bool searchAgain, bool escapeSequence ) { + auto listBox = mGlobalSearchHistoryList->getListBox(); + + if ( !searchAgain ) { + mGlobalSearchHistory.push_back( std::make_pair( search, model ) ); + if ( mGlobalSearchHistory.size() > 10 ) + mGlobalSearchHistory.pop_front(); + + std::vector items; + for ( auto item = mGlobalSearchHistory.rbegin(); item != mGlobalSearchHistory.rend(); + item++ ) { + items.push_back( item->first ); + } + + listBox->clear(); + listBox->addListBoxItems( items ); + if ( mGlobalSearchHistoryOnItemSelectedCb ) + mGlobalSearchHistoryList->removeEventListener( mGlobalSearchHistoryOnItemSelectedCb ); + listBox->setSelected( 0 ); + mGlobalSearchHistoryOnItemSelectedCb = mGlobalSearchHistoryList->addEventListener( + Event::OnItemSelected, [&, searchReplace]( const Event* ) { + auto idx = mGlobalSearchHistoryList->getListBox()->getItemSelectedIndex(); + auto idxItem = mGlobalSearchHistory.at( mGlobalSearchHistory.size() - 1 - idx ); + updateGlobalSearchBarResults( idxItem.first, idxItem.second, searchReplace, + escapeSequence ); + } ); + } else if ( listBox->getItemSelectedIndex() < mGlobalSearchHistory.size() ) { + mGlobalSearchHistory[mGlobalSearchHistory.size() - 1 - listBox->getItemSelectedIndex()] + .second = model; + } +} + void GlobalSearchController::doGlobalSearch( String text, bool caseSensitive, bool wholeWord, bool luaPattern, bool escapeSequence, bool searchReplace, bool searchAgain ) { @@ -439,41 +491,8 @@ void GlobalSearchController::doGlobalSearch( String text, bool caseSensitive, bo mUISceneNode->runOnMainThread( [&, loader, res, search, searchReplace, searchAgain, escapeSequence] { auto model = ProjectSearch::asModel( res ); - auto listBox = mGlobalSearchHistoryList->getListBox(); - - if ( !searchAgain ) { - mGlobalSearchHistory.push_back( std::make_pair( search, model ) ); - if ( mGlobalSearchHistory.size() > 10 ) - mGlobalSearchHistory.pop_front(); - - std::vector items; - for ( auto item = mGlobalSearchHistory.rbegin(); - item != mGlobalSearchHistory.rend(); item++ ) { - items.push_back( item->first ); - } - - listBox->clear(); - listBox->addListBoxItems( items ); - if ( mGlobalSearchHistoryOnItemSelectedCb ) - mGlobalSearchHistoryList->removeEventListener( - mGlobalSearchHistoryOnItemSelectedCb ); - listBox->setSelected( 0 ); - mGlobalSearchHistoryOnItemSelectedCb = - mGlobalSearchHistoryList->addEventListener( - Event::OnItemSelected, [&, searchReplace]( const Event* ) { - auto idx = mGlobalSearchHistoryList->getListBox() - ->getItemSelectedIndex(); - auto idxItem = mGlobalSearchHistory.at( - mGlobalSearchHistory.size() - 1 - idx ); - updateGlobalSearchBarResults( idxItem.first, idxItem.second, - searchReplace, escapeSequence ); - } ); - } else if ( listBox->getItemSelectedIndex() < mGlobalSearchHistory.size() ) { - mGlobalSearchHistory[mGlobalSearchHistory.size() - 1 - - listBox->getItemSelectedIndex()] - .second = model; - } - + updateGlobalSearchHistory( model, search, searchReplace, searchAgain, + escapeSequence ); updateGlobalSearchBarResults( search, model, searchReplace, escapeSequence ); loader->setVisible( false ); loader->close(); @@ -486,11 +505,11 @@ void GlobalSearchController::doGlobalSearch( String text, bool caseSensitive, bo } void GlobalSearchController::onLoadDone( const Variant& lineNum, const Variant& colNum ) { - if ( mEditorSplitter->curEditorExistsAndFocused() && lineNum.isValid() && colNum.isValid() && + if ( mSplitter->curEditorExistsAndFocused() && lineNum.isValid() && colNum.isValid() && lineNum.is( Variant::Type::Int64 ) && colNum.is( Variant::Type::Int64 ) ) { TextPosition pos{ lineNum.asInt64(), colNum.asInt64() }; - mEditorSplitter->getCurEditor()->getDocument().setSelection( pos ); - mEditorSplitter->getCurEditor()->goToLine( pos ); + mSplitter->getCurEditor()->getDocument().setSelection( pos ); + mSplitter->getCurEditor()->goToLine( pos ); hideGlobalSearchBar(); } } @@ -529,7 +548,7 @@ void GlobalSearchController::initGlobalSearchTree( UITreeViewGlobalSearch* searc ModelRole::Custom ) ); if ( vPath.isValid() && vPath.is( Variant::Type::cstr ) ) { std::string path( vPath.asCStr() ); - UITab* tab = mEditorSplitter->isDocumentOpen( path ); + UITab* tab = mSplitter->isDocumentOpen( path ); Variant lineNum( model->data( model->index( modelEvent->getModelIndex().row(), ProjectSearch::ResultModel::FileOrPosition, @@ -556,4 +575,41 @@ void GlobalSearchController::initGlobalSearchTree( UITreeViewGlobalSearch* searc } ); } +PluginRequestHandle GlobalSearchController::processMessage( const PluginMessage& msg ) { + if ( msg.type != PluginMessageType::SymbolReference || !msg.isBroadcast() ) + return {}; + + const ProjectSearch::Result& res = msg.asProjectSearchResult(); + if ( res.empty() ) + return {}; + auto model = ProjectSearch::asModel( res ); + model->removeLastNewLineCharacter(); + model->setResultFromSymbolReference( true ); + ProjectSearch::ResultData::Result sample; + + for ( const auto& r : res ) { + if ( !r.results.empty() ) { + sample = r.results.front(); + break; + } + } + + if ( sample.line.empty() ) + return {}; + + if ( sample.position.end().column() - sample.position.start().column() <= 0 ) + return {}; + + auto search = + sample.line.substr( sample.position.start().column(), + sample.position.end().column() - sample.position.start().column() ); + + showGlobalSearch( false ); + mGlobalSearchInput->setText( search ); + updateGlobalSearchHistory( model, search, false, false, false ); + updateGlobalSearchBarResults( search, model, false, false ); + + return {}; +} + } // namespace ecode diff --git a/src/tools/ecode/globalsearchcontroller.hpp b/src/tools/ecode/globalsearchcontroller.hpp index 6ad83b321..7ff970974 100644 --- a/src/tools/ecode/globalsearchcontroller.hpp +++ b/src/tools/ecode/globalsearchcontroller.hpp @@ -2,6 +2,7 @@ #define ECODE_GLOBALSEARCHCONTROLLER_HPP #include "appconfig.hpp" +#include "plugins/pluginmanager.hpp" #include "projectsearch.hpp" #include @@ -63,7 +64,7 @@ class GlobalSearchController { GlobalSearchBarConfig getGlobalSearchBarConfig() const; protected: - UICodeEditorSplitter* mEditorSplitter{ nullptr }; + UICodeEditorSplitter* mSplitter{ nullptr }; UISceneNode* mUISceneNode{ nullptr }; App* mApp{ nullptr }; @@ -79,6 +80,12 @@ class GlobalSearchController { mGlobalSearchHistory; void onLoadDone( const Variant& lineNum, const Variant& colNum ); + + PluginRequestHandle processMessage( const PluginMessage& msg ); + + void updateGlobalSearchHistory( std::shared_ptr model, + const std::string& search, bool searchReplace, bool searchAgain, + bool escapeSequence ); }; } // namespace ecode diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp index 10a13306e..a6186b066 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -306,7 +306,8 @@ void LSPClientPlugin::loadLSPConfig( std::vector& lsps, const std auto& kb = j["keybindings"]; auto list = { "lsp-go-to-definition", "lsp-go-to-declaration", "lsp-go-to-implementation", "lsp-go-to-type-definition", - "lsp-switch-header-source", "lsp-symbol-info" }; + "lsp-switch-header-source", "lsp-symbol-info", + "lsp-symbol-references" }; for ( const auto& key : list ) { if ( kb.contains( key ) ) { if ( !kb[key].empty() ) @@ -442,31 +443,36 @@ void LSPClientPlugin::onRegister( UICodeEditor* editor ) { } if ( editor->hasDocument() ) { - editor->getDocument().setCommand( "lsp-go-to-definition", [&, editor]() { + auto& doc = editor->getDocument(); + + doc.setCommand( "lsp-go-to-definition", [&, editor]() { mClientManager.getAndGoToLocation( editor->getDocumentRef(), "textDocument/definition" ); } ); - editor->getDocument().setCommand( "lsp-go-to-declaration", [&, editor]() { + doc.setCommand( "lsp-go-to-declaration", [&, editor]() { mClientManager.getAndGoToLocation( editor->getDocumentRef(), "textDocument/declaration" ); } ); - editor->getDocument().setCommand( "lsp-go-to-implementation", [&, editor]() { + doc.setCommand( "lsp-go-to-implementation", [&, editor]() { mClientManager.getAndGoToLocation( editor->getDocumentRef(), "textDocument/implementation" ); } ); - editor->getDocument().setCommand( "lsp-go-to-type-definition", [&, editor]() { + doc.setCommand( "lsp-go-to-type-definition", [&, editor]() { mClientManager.getAndGoToLocation( editor->getDocumentRef(), "textDocument/typeDefinition" ); } ); - editor->getDocument().setCommand( "lsp-switch-header-source", - [&, editor]() { switchSourceHeader( editor ); } ); + doc.setCommand( "lsp-switch-header-source", + [&, editor]() { switchSourceHeader( editor ); } ); - editor->getDocument().setCommand( "lsp-symbol-info", - [&, editor]() { getSymbolInfo( editor ); } ); + doc.setCommand( "lsp-symbol-info", [&, editor]() { getSymbolInfo( editor ); } ); + + doc.setCommand( "lsp-symbol-references", [&, editor] { + mClientManager.getSymbolReferences( editor->getDocumentRef() ); + } ); } std::vector listeners; @@ -573,6 +579,9 @@ bool LSPClientPlugin::onCreateContextMenu( UICodeEditor* editor, UIPopUpMenu* me if ( cap.implementationProvider ) addFn( "lsp-go-to-implementation", "Go To Implementation" ); + if ( cap.referencesProvider ) + addFn( "lsp-symbol-references", "Find References to Symbol Under Cursor" ); + if ( server->getDefinition().language == "cpp" || server->getDefinition().language == "c" ) addFn( "lsp-switch-header-source", "Switch Header/Source" ); diff --git a/src/tools/ecode/plugins/lsp/lspclientserver.cpp b/src/tools/ecode/plugins/lsp/lspclientserver.cpp index a87e70f76..9fe52d770 100644 --- a/src/tools/ecode/plugins/lsp/lspclientserver.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientserver.cpp @@ -168,12 +168,10 @@ static LSPLocation parseLocationLink( const json& loc ) { static std::vector parseDocumentLocation( const json& result ) { std::vector ret; if ( result.is_array() ) { - const auto& locs = result; - for ( const auto& def : locs ) { - const auto& ob = def; - ret.push_back( parseLocation( ob ) ); + for ( const auto& def : result ) { + ret.push_back( parseLocation( def ) ); if ( ret.back().uri.empty() ) - ret.back() = parseLocationLink( ob ); + ret.back() = parseLocationLink( def ); } } else if ( result.is_object() ) { ret.push_back( parseLocation( result ) ); @@ -197,7 +195,9 @@ static json textDocumentPositionParams( const URI& document, TextPosition pos ) static json referenceParams( const URI& document, TextPosition pos, bool decl ) { auto params = textDocumentPositionParams( document, pos ); - params["context"] = json{ { "includeDeclaration", decl } }; + json refCtx; + refCtx["includeDeclaration"] = decl; + params["context"] = refCtx; return params; } @@ -301,6 +301,7 @@ static void fromJson( LSPServerCapabilities& caps, const json& json ) { caps.documentSymbolProvider = toBoolOrObject( json, "documentSymbolProvider" ); caps.documentHighlightProvider = toBoolOrObject( json, "documentHighlightProvider" ); caps.documentFormattingProvider = toBoolOrObject( json, "documentFormattingProvider" ); + caps.workspaceSymbolProvider = toBoolOrObject( json, "workspaceSymbolProvider" ); if ( json.contains( "documentRangeFormattingProvider" ) ) caps.documentRangeFormattingProvider = toBoolOrObject( json, "documentRangeFormattingProvider" ); diff --git a/src/tools/ecode/plugins/lsp/lspclientserver.hpp b/src/tools/ecode/plugins/lsp/lspclientserver.hpp index 43ac12a5d..9b4f8a482 100644 --- a/src/tools/ecode/plugins/lsp/lspclientserver.hpp +++ b/src/tools/ecode/plugins/lsp/lspclientserver.hpp @@ -149,6 +149,9 @@ class LSPClientServer { LSPRequestHandle documentReferences( const URI& document, const TextPosition& pos, bool decl, const JsonReplyHandler& h ); + LSPRequestHandle documentReferences( const URI& document, const TextPosition& pos, bool decl, + const LocationHandler& h ); + LSPRequestHandle documentCompletion( const URI& document, const TextPosition& pos, const JsonReplyHandler& h ); @@ -187,10 +190,6 @@ class LSPClientServer { void removeDoc( TextDocument* doc ); - LSPClientServer::LSPRequestHandle documentReferences( const URI& document, - const TextPosition& pos, bool decl, - const LocationHandler& h ); - protected: LSPClientServerManager* mManager{ nullptr }; String::HashType mId; diff --git a/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp b/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp index d0d90c8d2..5eb7f8ac6 100644 --- a/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientservermanager.cpp @@ -1,4 +1,5 @@ #include "lspclientservermanager.hpp" +#include "../../projectsearch.hpp" #include "lspclientplugin.hpp" #include #include @@ -237,6 +238,47 @@ void LSPClientServerManager::setLSPDecayTime( const Time& lSPDecayTime ) { mLSPDecayTime = lSPDecayTime; } +void LSPClientServerManager::sendSymbolReferenceBroadcast( const std::vector& resp ) { + if ( resp.empty() ) + return; + + std::map res; + + for ( auto& r : resp ) { + auto& rd = res[r.uri.getPath()]; + if ( rd.file.empty() ) + rd.file = r.uri.getPath(); + auto curDoc = mPluginManager->getSplitter()->findDocFromPath( r.uri.getPath() ); + if ( !curDoc ) + continue; + + ProjectSearch::ResultData::Result rs( curDoc->line( r.range.start().line() ).getText(), + r.range, -1, -1 ); + + rd.results.emplace_back( std::move( rs ) ); + } + + ProjectSearch::Result result; + for ( auto& r : res ) { + if ( !r.second.results.empty() ) + result.emplace_back( std::move( r.second ) ); + } + + mPluginManager->sendBroadcast( PluginMessageType::SymbolReference, + PluginMessageFormat::ProjectSearchResult, &result ); +} + +void LSPClientServerManager::getSymbolReferences( std::shared_ptr doc ) { + auto* server = getOneLSPClientServer( doc ); + if ( !server ) + return; + server->documentReferences( + doc->getURI(), doc->getSelection().start(), true, + [this]( const PluginIDType&, const std::vector& resp ) { + sendSymbolReferenceBroadcast( resp ); + } ); +} + void LSPClientServerManager::didChangeWorkspaceFolders( const std::string& folder ) { mLSPWorkspaceFolder = { "file://" + folder, FileSystem::fileNameFromPath( folder ) }; Lock l( mClientsMutex ); diff --git a/src/tools/ecode/plugins/lsp/lspclientservermanager.hpp b/src/tools/ecode/plugins/lsp/lspclientservermanager.hpp index f72a99252..2b004c470 100644 --- a/src/tools/ecode/plugins/lsp/lspclientservermanager.hpp +++ b/src/tools/ecode/plugins/lsp/lspclientservermanager.hpp @@ -64,6 +64,8 @@ class LSPClientServerManager { void setLSPDecayTime( const Time& lSPDecayTime ); + void getSymbolReferences( std::shared_ptr doc ); + protected: friend class LSPClientServer; PluginManager* mPluginManager{ nullptr }; @@ -89,6 +91,8 @@ class LSPClientServerManager { void closeLSPServer( const String::HashType& id ); void goToLocation( const LSPLocation& loc ); + + void sendSymbolReferenceBroadcast( const std::vector& resp ); }; } // namespace ecode diff --git a/src/tools/ecode/plugins/lsp/lspprotocol.hpp b/src/tools/ecode/plugins/lsp/lspprotocol.hpp index 8da284849..af2fba807 100644 --- a/src/tools/ecode/plugins/lsp/lspprotocol.hpp +++ b/src/tools/ecode/plugins/lsp/lspprotocol.hpp @@ -101,6 +101,7 @@ struct LSPServerCapabilities { bool documentHighlightProvider = false; bool documentFormattingProvider = false; bool documentRangeFormattingProvider = false; + bool workspaceSymbolProvider = false; LSPDocumentOnTypeFormattingOptions documentOnTypeFormattingProvider; bool renameProvider = false; // CodeActionOptions not useful/considered at present diff --git a/src/tools/ecode/plugins/pluginmanager.hpp b/src/tools/ecode/plugins/pluginmanager.hpp index 73acc9bc0..2f938e6dc 100644 --- a/src/tools/ecode/plugins/pluginmanager.hpp +++ b/src/tools/ecode/plugins/pluginmanager.hpp @@ -1,6 +1,7 @@ #ifndef ECODE_PLUGINMANAGER_HPP #define ECODE_PLUGINMANAGER_HPP +#include "../projectsearch.hpp" #include "lsp/lspprotocol.hpp" #include #include @@ -68,6 +69,7 @@ enum class PluginMessageType { CancelRequest, // Cancel a request ID FindAndOpenClosestURI, // Request a component to find and open the closest path from an URI DocumentFormatting, // Request the LSP Server to format a document + SymbolReference, // Request the LSP Server to find a symbol reference in the project Undefined }; @@ -77,7 +79,7 @@ enum class PluginMessageFormat { CodeCompletion, LanguageServerCapabilities, SignatureHelp, - DocumentFormatting + ProjectSearchResult }; class PluginIDType { @@ -153,6 +155,10 @@ struct PluginMessage { return *static_cast( data ); } + const ProjectSearch::Result& asProjectSearchResult() const { + return *static_cast( data ); + } + const PluginIDType& asPluginID() const { return *static_cast( data ); } bool isResponse() const { return -1 != responseID && 0 != responseID; } diff --git a/src/tools/ecode/projectsearch.cpp b/src/tools/ecode/projectsearch.cpp index f9bf04f28..a3518967d 100644 --- a/src/tools/ecode/projectsearch.cpp +++ b/src/tools/ecode/projectsearch.cpp @@ -29,8 +29,8 @@ static String textLine( const std::string& fileText, const size_t& fromPos, size nlStartPtr++; while ( ++endPtr && *endPtr != '\0' && *endPtr != '\n' ) { } - relCol = String::utf8Length( - fileText.substr( nlStartPtr - stringStartPtr, startPtr - nlStartPtr ) ); + relCol = + String::utf8Length( fileText.substr( nlStartPtr - stringStartPtr, startPtr - nlStartPtr ) ); // if the line to substract is massive we only get the fist kilobyte of that line, since the // line is only shared for visual aid. return fileText.substr( nlStartPtr - stringStartPtr, @@ -65,12 +65,11 @@ searchInFileHorspool( const std::string& file, const std::string& text, const bo totNl += countNewLines( fileText, lSearchRes, searchRes ); String str( textLine( caseSensitive ? fileText : fileTextOriginal, searchRes, relCol ) ); - res.push_back( - { str, - { { (Int64)totNl, (Int64)relCol }, - { (Int64)totNl, (Int64)( relCol + String::utf8Length( text ) ) } }, - searchRes, - static_cast( searchRes + text.size() ) } ); + res.push_back( { str, + { { (Int64)totNl, (Int64)relCol }, + { (Int64)totNl, (Int64)( relCol + String::utf8Length( text ) ) } }, + searchRes, + static_cast( searchRes + text.size() ) } ); lSearchRes = searchRes; searchRes += text.size(); } @@ -185,4 +184,12 @@ void ProjectSearch::find( const std::vector files, std::string stri } } +void ProjectSearch::ResultModel::removeLastNewLineCharacter() { + for ( auto& r : mResult ) { + for ( auto& r2 : r.results ) + if ( !r2.line.empty() && r2.line.back() == '\n' ) + r2.line.pop_back(); + } +} + } // namespace ecode diff --git a/src/tools/ecode/projectsearch.hpp b/src/tools/ecode/projectsearch.hpp index a7b1f4eb1..10ae7b7a9 100644 --- a/src/tools/ecode/projectsearch.hpp +++ b/src/tools/ecode/projectsearch.hpp @@ -22,10 +22,11 @@ class ProjectSearch { struct Result { Result( const String& line, const TextRange& pos, Int64 s, Int64 e ) : line( line ), position( pos ), start( s ), end( e ) {} + Result() {} String line; TextRange position; - Int64 start; - Int64 end; + Int64 start{ 0 }; + Int64 end{ 0 }; bool selected{ true }; }; std::string file; @@ -185,8 +186,15 @@ class ProjectSearch { const Result& getResult() const { return mResult; } + void removeLastNewLineCharacter(); + + void setResultFromSymbolReference( bool ref ) { mResultFromSymbolReference = ref; } + + bool isResultFromSymbolReference() const { return mResultFromSymbolReference; } + protected: Result mResult; + bool mResultFromSymbolReference{ false }; }; static std::shared_ptr asModel( const Result& result ) {