mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-07-20 17:52:50 +03:00
ecode: Implemented LSP textDocument/references ("Find References to Symbol Under Cursor").
This commit is contained in:
@@ -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 );
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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<std::pair<Int64, Int64>>& 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<ProjectSearch::ResultModel> 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<std::pair<Int64, Int64>> 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<UICheckBox>( "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<ProjectSearch::ResultModel> 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<String> 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<String> 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
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define ECODE_GLOBALSEARCHCONTROLLER_HPP
|
||||
|
||||
#include "appconfig.hpp"
|
||||
#include "plugins/pluginmanager.hpp"
|
||||
#include "projectsearch.hpp"
|
||||
#include <eepp/ee.hpp>
|
||||
|
||||
@@ -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<ProjectSearch::ResultModel> model,
|
||||
const std::string& search, bool searchReplace, bool searchAgain,
|
||||
bool escapeSequence );
|
||||
};
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
@@ -306,7 +306,8 @@ void LSPClientPlugin::loadLSPConfig( std::vector<LSPDefinition>& 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<Uint32> 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" );
|
||||
|
||||
|
||||
@@ -168,12 +168,10 @@ static LSPLocation parseLocationLink( const json& loc ) {
|
||||
static std::vector<LSPLocation> parseDocumentLocation( const json& result ) {
|
||||
std::vector<LSPLocation> 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" );
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "lspclientservermanager.hpp"
|
||||
#include "../../projectsearch.hpp"
|
||||
#include "lspclientplugin.hpp"
|
||||
#include <algorithm>
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
@@ -237,6 +238,47 @@ void LSPClientServerManager::setLSPDecayTime( const Time& lSPDecayTime ) {
|
||||
mLSPDecayTime = lSPDecayTime;
|
||||
}
|
||||
|
||||
void LSPClientServerManager::sendSymbolReferenceBroadcast( const std::vector<LSPLocation>& resp ) {
|
||||
if ( resp.empty() )
|
||||
return;
|
||||
|
||||
std::map<std::string, ProjectSearch::ResultData> 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<TextDocument> doc ) {
|
||||
auto* server = getOneLSPClientServer( doc );
|
||||
if ( !server )
|
||||
return;
|
||||
server->documentReferences(
|
||||
doc->getURI(), doc->getSelection().start(), true,
|
||||
[this]( const PluginIDType&, const std::vector<LSPLocation>& resp ) {
|
||||
sendSymbolReferenceBroadcast( resp );
|
||||
} );
|
||||
}
|
||||
|
||||
void LSPClientServerManager::didChangeWorkspaceFolders( const std::string& folder ) {
|
||||
mLSPWorkspaceFolder = { "file://" + folder, FileSystem::fileNameFromPath( folder ) };
|
||||
Lock l( mClientsMutex );
|
||||
|
||||
@@ -64,6 +64,8 @@ class LSPClientServerManager {
|
||||
|
||||
void setLSPDecayTime( const Time& lSPDecayTime );
|
||||
|
||||
void getSymbolReferences( std::shared_ptr<TextDocument> 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<LSPLocation>& resp );
|
||||
};
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef ECODE_PLUGINMANAGER_HPP
|
||||
#define ECODE_PLUGINMANAGER_HPP
|
||||
|
||||
#include "../projectsearch.hpp"
|
||||
#include "lsp/lspprotocol.hpp"
|
||||
#include <eepp/ui/models/model.hpp>
|
||||
#include <eepp/ui/tools/uicodeeditorsplitter.hpp>
|
||||
@@ -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<const LSPSignatureHelp*>( data );
|
||||
}
|
||||
|
||||
const ProjectSearch::Result& asProjectSearchResult() const {
|
||||
return *static_cast<const ProjectSearch::Result*>( data );
|
||||
}
|
||||
|
||||
const PluginIDType& asPluginID() const { return *static_cast<const PluginIDType*>( data ); }
|
||||
|
||||
bool isResponse() const { return -1 != responseID && 0 != responseID; }
|
||||
|
||||
@@ -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<Int64>( searchRes + text.size() ) } );
|
||||
res.push_back( { str,
|
||||
{ { (Int64)totNl, (Int64)relCol },
|
||||
{ (Int64)totNl, (Int64)( relCol + String::utf8Length( text ) ) } },
|
||||
searchRes,
|
||||
static_cast<Int64>( searchRes + text.size() ) } );
|
||||
lSearchRes = searchRes;
|
||||
searchRes += text.size();
|
||||
}
|
||||
@@ -185,4 +184,12 @@ void ProjectSearch::find( const std::vector<std::string> 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
|
||||
|
||||
@@ -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<ResultModel> asModel( const Result& result ) {
|
||||
|
||||
Reference in New Issue
Block a user