ecode: Minor LSP improvements.

This commit is contained in:
Martín Lucas Golini
2023-02-05 12:59:05 -03:00
parent ecba3fa9aa
commit ca84455fcc
6 changed files with 77 additions and 19 deletions
+1 -1
View File
@@ -53,7 +53,7 @@
"language": "c",
"name": "clangd",
"url": "https://clang.llvm.org/extra/clangd/",
"command": "clangd -log=error --background-index --limit-results=500 --completion-style=bundled",
"command": "clangd -log=error --background-index --header-insertion=never --limit-results=0 --limit-references=0 --clang-tidy=0 --use-dirty-headers --completion-style=bundled -j=$NPROC",
"file_patterns": ["%.c$", "%.h$", "%.C$", "%.H$", "%.objc$"]
},
{
+44 -15
View File
@@ -71,6 +71,10 @@ static LSPURIAndServer getServerURIFromTextDocumentURI( LSPClientServerManager&
return { uri, manager.getOneLSPClientServer( uri ) };
}
static void sanitizeCommand( std::string& cmd ) {
String::replaceAll( cmd, "$NPROC", String::toString( Sys::getCPUCount() ) );
}
LSPPositionAndServer getLSPLocationFromJSON( LSPClientServerManager& manager, const json& data ) {
if ( !data.contains( "uri" ) || !data.contains( "position" ) )
return {};
@@ -307,7 +311,7 @@ void LSPClientPlugin::loadLSPConfig( std::vector<LSPDefinition>& lsps, const std
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-symbol-references" };
"lsp-symbol-references", "lsp-memory-usage" };
for ( const auto& key : list ) {
if ( kb.contains( key ) ) {
if ( !kb[key].empty() )
@@ -326,34 +330,47 @@ void LSPClientPlugin::loadLSPConfig( std::vector<LSPDefinition>& lsps, const std
auto& servers = j["servers"];
for ( auto& obj : servers ) {
bool lspOverwritten = false;
// Allow disabling an LSP by redeclaring it in the user configuration file.
if ( obj.contains( "name" ) && obj.contains( "disabled" ) &&
obj.at( "disabled" ).is_boolean() ) {
for ( auto& lsp : lsps ) {
if ( lsp.name == obj["name"] ) {
lsp.disabled = obj["disabled"].get<bool>();
break;
if ( updateConfigFile && ( obj.contains( "name" ) || obj.contains( "use" ) ) &&
obj.contains( "disabled" ) && obj.at( "disabled" ).is_boolean() ) {
std::string name = obj.contains( "name" ) ? obj["name"] : obj["use"];
for ( auto& lspD : lsps ) {
if ( lspD.name == name ) {
lspD.disabled = obj["disabled"].get<bool>();
lspOverwritten = true;
}
}
}
// Allow overriding the command for already defined LSP
// And allow adding parameters to the already defined LSP
if ( obj.contains( "name" ) &&
if ( updateConfigFile && ( obj.contains( "name" ) || obj.contains( "use" ) ) &&
( ( obj.contains( "command" ) && obj.at( "command" ).is_string() ) ||
( obj.contains( "command_parameters" ) &&
obj.at( "command_parameters" ).is_string() ) ) ) {
for ( auto& lsp : lsps ) {
if ( lsp.name == obj["name"] ) {
if ( !obj.value( "command", "" ).empty() )
lsp.command = obj.value( "command", "" );
if ( !obj.value( "command_parameters", "" ).empty() )
lsp.commandParameters = obj.value( "command_parameters", "" );
break;
for ( auto& lspR : lsps ) {
std::string name = obj.contains( "name" ) ? obj["name"] : obj["use"];
if ( lspR.name == name ) {
lspOverwritten = true;
if ( !obj.value( "command", "" ).empty() ) {
lspR.command = obj.value( "command", "" );
sanitizeCommand( lspR.command );
}
if ( !obj.value( "command_parameters", "" ).empty() ) {
std::string cmdParam( obj.value( "command_parameters", "" ) );
if ( !cmdParam.empty() && cmdParam.front() != ' ' )
cmdParam = " " + cmdParam;
lspR.commandParameters += cmdParam;
sanitizeCommand( lspR.commandParameters );
}
}
}
}
if ( lspOverwritten )
continue;
if ( !obj.contains( "language" ) || !obj.contains( "file_patterns" ) ) {
Log::warning( "LSP server without language or file_patterns, ignored..." );
continue;
@@ -408,6 +425,9 @@ void LSPClientPlugin::loadLSPConfig( std::vector<LSPDefinition>& lsps, const std
lsp.rootIndicationFileNames.push_back( fn );
}
sanitizeCommand( lsp.command );
sanitizeCommand( lsp.commandParameters );
// If the file pattern is repeated, we will overwrite the previous LSP.
// The previous LSP should be the "default" LSP that comes with ecode.
size_t pos = lspFilePatternPosition( lsps, lsp.filePatterns );
@@ -473,6 +493,10 @@ void LSPClientPlugin::onRegister( UICodeEditor* editor ) {
doc.setCommand( "lsp-symbol-references", [&, editor] {
mClientManager.getSymbolReferences( editor->getDocumentRef() );
} );
doc.setCommand( "lsp-memory-usage", [&, editor] {
mClientManager.memoryUsage( editor->getDocumentRef() );
} );
}
std::vector<Uint32> listeners;
@@ -585,6 +609,11 @@ bool LSPClientPlugin::onCreateContextMenu( UICodeEditor* editor, UIPopUpMenu* me
if ( server->getDefinition().language == "cpp" || server->getDefinition().language == "c" )
addFn( "lsp-switch-header-source", "Switch Header/Source" );
#ifdef EE_DEBUG
if ( server->getDefinition().name == "clangd" )
addFn( "lsp-memory-usage", "LSP Memory Usage" );
#endif
return false;
}
@@ -892,8 +892,13 @@ LSPClientServer::~LSPClientServer() {
}
bool LSPClientServer::start() {
bool ret = mProcess.create( mLSP.command + mLSP.commandParameters, Process::getDefaultOptions(),
{}, mRootPath );
std::string cmd( mLSP.command );
if ( !mLSP.commandParameters.empty() ) {
if ( mLSP.commandParameters.front() != ' ' )
mLSP.commandParameters = " " + mLSP.commandParameters;
cmd += mLSP.commandParameters;
}
bool ret = mProcess.create( cmd, Process::getDefaultOptions(), {}, mRootPath );
if ( ret && mProcess.isAlive() ) {
mProcess.startAsyncRead(
[this]( const char* bytes, size_t n ) { readStdOut( bytes, n ); },
@@ -1216,7 +1221,6 @@ void LSPClientServer::processNotification( const json& msg ) {
} else if ( method == ( "$/progress" ) ) {
workDoneProgress( parseWorkDone( msg[MEMBER_PARAMS] ) );
return;
} else {
}
Log::debug( "LSPClientServer::processNotification server %s: %s", mLSP.name.c_str(),
msg.dump().c_str() );
@@ -1557,6 +1561,16 @@ LSPClientServer::documentFormatting( const URI& document, const json& options,
} );
}
LSPClientServer::LSPRequestHandle LSPClientServer::memoryUsage( const JsonReplyHandler& h ) {
return send( newRequest( "$/memoryUsage" ), h );
}
LSPClientServer::LSPRequestHandle LSPClientServer::memoryUsage() {
return memoryUsage( []( const IdType&, const json& json ) {
Log::warning( "Received Memory Usage Information:\n%s", json.dump( 2 ).c_str() );
} );
}
LSPClientServer::LSPRequestHandle
LSPClientServer::documentSemanticTokensFull( const URI& document, bool delta,
const std::string& requestId, const TextRange& range,
@@ -1575,4 +1589,5 @@ LSPClientServer::documentSemanticTokensFull( const URI& document, bool delta,
return send( newRequest( "textDocument/semanticTokens/full", params ), h );
}
} // namespace ecode
@@ -188,6 +188,11 @@ class LSPClientServer {
LSPRequestHandle documentFormatting( const URI& document, const json& options,
const TextEditArrayHandler& h );
LSPRequestHandle memoryUsage( const JsonReplyHandler& h );
LSPRequestHandle memoryUsage();
void removeDoc( TextDocument* doc );
protected:
@@ -279,6 +279,13 @@ void LSPClientServerManager::getSymbolReferences( std::shared_ptr<TextDocument>
} );
}
void LSPClientServerManager::memoryUsage( std::shared_ptr<TextDocument> doc ) {
auto* server = getOneLSPClientServer( doc );
if ( !server )
return;
server->memoryUsage();
}
void LSPClientServerManager::didChangeWorkspaceFolders( const std::string& folder ) {
mLSPWorkspaceFolder = { "file://" + folder, FileSystem::fileNameFromPath( folder ) };
Lock l( mClientsMutex );
@@ -66,6 +66,8 @@ class LSPClientServerManager {
void getSymbolReferences( std::shared_ptr<TextDocument> doc );
void memoryUsage( std::shared_ptr<TextDocument> doc );
protected:
friend class LSPClientServer;
PluginManager* mPluginManager{ nullptr };