ecode: Implemented LSP textDocument/references ("Find References to Symbol Under Cursor").

This commit is contained in:
Martín Lucas Golini
2023-02-05 03:26:13 -03:00
parent 3aaf5dc48a
commit ecba3fa9aa
14 changed files with 250 additions and 87 deletions

View File

@@ -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" );

View File

@@ -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" );

View File

@@ -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;

View File

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

View File

@@ -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

View File

@@ -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

View File

@@ -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; }