mirror of
https://github.com/RGBCube/serenity
synced 2025-07-23 19:37:34 +00:00
LanguageServers/Cpp: Update client asynchronously about symbols
As a document is parsed, the language server updates the client asynchronously about symbol declarations it finds.
This commit is contained in:
parent
71c7597130
commit
a94b5376bc
12 changed files with 83 additions and 19 deletions
|
@ -110,7 +110,7 @@ inline bool decode(Decoder& decoder, GUI::AutocompleteProvider::Declaration& dec
|
||||||
if (!decode(decoder, declaration.position))
|
if (!decode(decoder, declaration.position))
|
||||||
return false;
|
return false;
|
||||||
u32 type;
|
u32 type;
|
||||||
if (!decoder.decode( type))
|
if (!decoder.decode(type))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
declaration.type = static_cast<GUI::AutocompleteProvider::DeclarationType>(type);
|
declaration.type = static_cast<GUI::AutocompleteProvider::DeclarationType>(type);
|
||||||
|
|
|
@ -91,6 +91,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
virtual void handle(const Messages::LanguageClient::AutoCompleteSuggestions&) override;
|
virtual void handle(const Messages::LanguageClient::AutoCompleteSuggestions&) override;
|
||||||
virtual void handle(const Messages::LanguageClient::DeclarationLocation&) override;
|
virtual void handle(const Messages::LanguageClient::DeclarationLocation&) override;
|
||||||
|
virtual void handle(const Messages::LanguageClient::DeclarationsInDocument&) override;
|
||||||
|
|
||||||
String m_project_path;
|
String m_project_path;
|
||||||
WeakPtr<LanguageClient> m_language_client;
|
WeakPtr<LanguageClient> m_language_client;
|
||||||
|
|
|
@ -26,11 +26,20 @@
|
||||||
|
|
||||||
#include "AutoCompleteEngine.h"
|
#include "AutoCompleteEngine.h"
|
||||||
|
|
||||||
AutoCompleteEngine::AutoCompleteEngine(const FileDB& filedb)
|
namespace LanguageServers::Cpp {
|
||||||
: m_filedb(filedb)
|
|
||||||
|
AutoCompleteEngine::AutoCompleteEngine(ClientConnection& connection, const FileDB& filedb)
|
||||||
|
: m_connection(connection)
|
||||||
|
, m_filedb(filedb)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoCompleteEngine::~AutoCompleteEngine()
|
AutoCompleteEngine::~AutoCompleteEngine()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
void AutoCompleteEngine::set_declarations_of_document(const String& filename, Vector<GUI::AutocompleteProvider::Declaration>&& declarations)
|
||||||
|
{
|
||||||
|
VERIFY(set_declarations_of_document_callback);
|
||||||
|
set_declarations_of_document_callback(m_connection, filename, move(declarations));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -31,9 +31,13 @@
|
||||||
#include <LibGUI/AutocompleteProvider.h>
|
#include <LibGUI/AutocompleteProvider.h>
|
||||||
#include <LibGUI/TextPosition.h>
|
#include <LibGUI/TextPosition.h>
|
||||||
|
|
||||||
|
namespace LanguageServers::Cpp {
|
||||||
|
|
||||||
|
class ClientConnection;
|
||||||
|
|
||||||
class AutoCompleteEngine {
|
class AutoCompleteEngine {
|
||||||
public:
|
public:
|
||||||
AutoCompleteEngine(const FileDB& filedb);
|
AutoCompleteEngine(ClientConnection&, const FileDB& filedb);
|
||||||
virtual ~AutoCompleteEngine();
|
virtual ~AutoCompleteEngine();
|
||||||
|
|
||||||
virtual Vector<GUI::AutocompleteProvider::Entry> get_suggestions(const String& file, const GUI::TextPosition& autocomplete_position) = 0;
|
virtual Vector<GUI::AutocompleteProvider::Entry> get_suggestions(const String& file, const GUI::TextPosition& autocomplete_position) = 0;
|
||||||
|
@ -44,9 +48,15 @@ public:
|
||||||
|
|
||||||
virtual Optional<GUI::AutocompleteProvider::ProjectLocation> find_declaration_of(const String&, const GUI::TextPosition&) { return {}; };
|
virtual Optional<GUI::AutocompleteProvider::ProjectLocation> find_declaration_of(const String&, const GUI::TextPosition&) { return {}; };
|
||||||
|
|
||||||
|
public:
|
||||||
|
Function<void(ClientConnection&, String, Vector<GUI::AutocompleteProvider::Declaration>)> set_declarations_of_document_callback;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const FileDB& filedb() const { return m_filedb; }
|
const FileDB& filedb() const { return m_filedb; }
|
||||||
|
void set_declarations_of_document(const String&, Vector<GUI::AutocompleteProvider::Declaration>&&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
ClientConnection& m_connection;
|
||||||
const FileDB& m_filedb;
|
const FileDB& m_filedb;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -40,7 +40,8 @@ ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> socket, int
|
||||||
: IPC::ClientConnection<LanguageClientEndpoint, LanguageServerEndpoint>(*this, move(socket), client_id)
|
: IPC::ClientConnection<LanguageClientEndpoint, LanguageServerEndpoint>(*this, move(socket), client_id)
|
||||||
{
|
{
|
||||||
s_connections.set(client_id, *this);
|
s_connections.set(client_id, *this);
|
||||||
m_autocomplete_engine = make<ParserAutoComplete>(m_filedb);
|
m_autocomplete_engine = make<ParserAutoComplete>(*this, m_filedb);
|
||||||
|
m_autocomplete_engine->set_declarations_of_document_callback = &ClientConnection::set_declarations_of_document_callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientConnection::~ClientConnection()
|
ClientConnection::~ClientConnection()
|
||||||
|
@ -132,9 +133,9 @@ void ClientConnection::handle(const Messages::LanguageServer::SetAutoCompleteMod
|
||||||
dbgln("SetAutoCompleteMode: {}", message.mode());
|
dbgln("SetAutoCompleteMode: {}", message.mode());
|
||||||
#endif
|
#endif
|
||||||
if (message.mode() == "Parser")
|
if (message.mode() == "Parser")
|
||||||
m_autocomplete_engine = make<ParserAutoComplete>(m_filedb);
|
m_autocomplete_engine = make<ParserAutoComplete>(*this, m_filedb);
|
||||||
else
|
else
|
||||||
m_autocomplete_engine = make<LexerAutoComplete>(m_filedb);
|
m_autocomplete_engine = make<LexerAutoComplete>(*this, m_filedb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientConnection::handle(const Messages::LanguageServer::FindDeclaration& message)
|
void ClientConnection::handle(const Messages::LanguageServer::FindDeclaration& message)
|
||||||
|
@ -156,4 +157,9 @@ void ClientConnection::handle(const Messages::LanguageServer::FindDeclaration& m
|
||||||
post_message(Messages::LanguageClient::DeclarationLocation(GUI::AutocompleteProvider::ProjectLocation { location.value().file, location.value().line, location.value().column }));
|
post_message(Messages::LanguageClient::DeclarationLocation(GUI::AutocompleteProvider::ProjectLocation { location.value().file, location.value().line, location.value().column }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClientConnection::set_declarations_of_document_callback(ClientConnection& instance, const String& filename, Vector<GUI::AutocompleteProvider::Declaration>&& declarations)
|
||||||
|
{
|
||||||
|
instance.post_message(Messages::LanguageClient::DeclarationsInDocument(filename, move(declarations)));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,8 @@ private:
|
||||||
virtual void handle(const Messages::LanguageServer::SetAutoCompleteMode&) override;
|
virtual void handle(const Messages::LanguageServer::SetAutoCompleteMode&) override;
|
||||||
virtual void handle(const Messages::LanguageServer::FindDeclaration&) override;
|
virtual void handle(const Messages::LanguageServer::FindDeclaration&) override;
|
||||||
|
|
||||||
|
static void set_declarations_of_document_callback(ClientConnection&, const String&, Vector<GUI::AutocompleteProvider::Declaration>&&);
|
||||||
|
|
||||||
FileDB m_filedb;
|
FileDB m_filedb;
|
||||||
OwnPtr<AutoCompleteEngine> m_autocomplete_engine;
|
OwnPtr<AutoCompleteEngine> m_autocomplete_engine;
|
||||||
};
|
};
|
||||||
|
|
|
@ -31,8 +31,8 @@
|
||||||
|
|
||||||
namespace LanguageServers::Cpp {
|
namespace LanguageServers::Cpp {
|
||||||
|
|
||||||
LexerAutoComplete::LexerAutoComplete(const FileDB& filedb)
|
LexerAutoComplete::LexerAutoComplete(ClientConnection& connection, const FileDB& filedb)
|
||||||
: AutoCompleteEngine(filedb)
|
: AutoCompleteEngine(connection, filedb)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ using namespace ::Cpp;
|
||||||
|
|
||||||
class LexerAutoComplete : public AutoCompleteEngine {
|
class LexerAutoComplete : public AutoCompleteEngine {
|
||||||
public:
|
public:
|
||||||
LexerAutoComplete(const FileDB& filedb);
|
LexerAutoComplete(ClientConnection&, const FileDB& filedb);
|
||||||
|
|
||||||
virtual Vector<GUI::AutocompleteProvider::Entry> get_suggestions(const String& file, const GUI::TextPosition& autocomplete_position) override;
|
virtual Vector<GUI::AutocompleteProvider::Entry> get_suggestions(const String& file, const GUI::TextPosition& autocomplete_position) override;
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "ParserAutoComplete.h"
|
#include "ParserAutoComplete.h"
|
||||||
#include <AK/Assertions.h>
|
#include <AK/Assertions.h>
|
||||||
#include <AK/HashTable.h>
|
#include <AK/HashTable.h>
|
||||||
|
#include <DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.h>
|
||||||
#include <LibCpp/AST.h>
|
#include <LibCpp/AST.h>
|
||||||
#include <LibCpp/Lexer.h>
|
#include <LibCpp/Lexer.h>
|
||||||
#include <LibCpp/Parser.h>
|
#include <LibCpp/Parser.h>
|
||||||
|
@ -35,8 +36,8 @@
|
||||||
|
|
||||||
namespace LanguageServers::Cpp {
|
namespace LanguageServers::Cpp {
|
||||||
|
|
||||||
ParserAutoComplete::ParserAutoComplete(const FileDB& filedb)
|
ParserAutoComplete::ParserAutoComplete(ClientConnection& connection, const FileDB& filedb)
|
||||||
: AutoCompleteEngine(filedb)
|
: AutoCompleteEngine(connection, filedb)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +72,9 @@ OwnPtr<ParserAutoComplete::DocumentData> ParserAutoComplete::create_document_dat
|
||||||
#ifdef CPP_LANGUAGE_SERVER_DEBUG
|
#ifdef CPP_LANGUAGE_SERVER_DEBUG
|
||||||
root->dump(0);
|
root->dump(0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
update_declared_symbols(*document_data);
|
||||||
|
|
||||||
return move(document_data);
|
return move(document_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,8 +83,9 @@ void ParserAutoComplete::set_document_data(const String& file, OwnPtr<DocumentDa
|
||||||
m_documents.set(filedb().to_absolute_path(file), move(data));
|
m_documents.set(filedb().to_absolute_path(file), move(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
ParserAutoComplete::DocumentData::DocumentData(String&& _text, const String& filename)
|
ParserAutoComplete::DocumentData::DocumentData(String&& _text, const String& _filename)
|
||||||
: text(move(_text))
|
: filename(_filename)
|
||||||
|
, text(move(_text))
|
||||||
, preprocessor(text.view())
|
, preprocessor(text.view())
|
||||||
, parser(preprocessor.process().view(), filename)
|
, parser(preprocessor.process().view(), filename)
|
||||||
{
|
{
|
||||||
|
@ -360,4 +365,26 @@ RefPtr<Declaration> ParserAutoComplete::find_declaration_of(const DocumentData&
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ParserAutoComplete::update_declared_symbols(const DocumentData& document)
|
||||||
|
{
|
||||||
|
Vector<GUI::AutocompleteProvider::Declaration> declarations;
|
||||||
|
for (auto& decl : document.parser.root_node()->declarations()) {
|
||||||
|
declarations.append({ decl.name(), { document.filename, decl.start().line, decl.start().column }, type_of_declaration(decl) });
|
||||||
|
}
|
||||||
|
set_declarations_of_document(document.filename, move(declarations));
|
||||||
|
}
|
||||||
|
|
||||||
|
GUI::AutocompleteProvider::DeclarationType ParserAutoComplete::type_of_declaration(const Declaration& decl)
|
||||||
|
{
|
||||||
|
if (decl.is_struct())
|
||||||
|
return GUI::AutocompleteProvider::DeclarationType::Struct;
|
||||||
|
if (decl.is_class())
|
||||||
|
return GUI::AutocompleteProvider::DeclarationType::Class;
|
||||||
|
if (decl.is_function())
|
||||||
|
return GUI::AutocompleteProvider::DeclarationType::Function;
|
||||||
|
if (decl.is_variable_declaration())
|
||||||
|
return GUI::AutocompleteProvider::DeclarationType::Variable;
|
||||||
|
return GUI::AutocompleteProvider::DeclarationType::Variable;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
#include "AutoCompleteEngine.h"
|
#include "AutoCompleteEngine.h"
|
||||||
#include "FileDB.h"
|
#include "FileDB.h"
|
||||||
|
#include <AK/Function.h>
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <DevTools/HackStudio/AutoCompleteResponse.h>
|
#include <DevTools/HackStudio/AutoCompleteResponse.h>
|
||||||
|
@ -42,7 +43,7 @@ using namespace ::Cpp;
|
||||||
|
|
||||||
class ParserAutoComplete : public AutoCompleteEngine {
|
class ParserAutoComplete : public AutoCompleteEngine {
|
||||||
public:
|
public:
|
||||||
ParserAutoComplete(const FileDB& filedb);
|
ParserAutoComplete(ClientConnection&, const FileDB& filedb);
|
||||||
|
|
||||||
virtual Vector<GUI::AutocompleteProvider::Entry> get_suggestions(const String& file, const GUI::TextPosition& autocomplete_position) override;
|
virtual Vector<GUI::AutocompleteProvider::Entry> get_suggestions(const String& file, const GUI::TextPosition& autocomplete_position) override;
|
||||||
virtual void on_edit(const String& file) override;
|
virtual void on_edit(const String& file) override;
|
||||||
|
@ -52,6 +53,7 @@ public:
|
||||||
private:
|
private:
|
||||||
struct DocumentData {
|
struct DocumentData {
|
||||||
DocumentData(String&& text, const String& filename);
|
DocumentData(String&& text, const String& filename);
|
||||||
|
String filename;
|
||||||
String text;
|
String text;
|
||||||
Preprocessor preprocessor;
|
Preprocessor preprocessor;
|
||||||
Parser parser;
|
Parser parser;
|
||||||
|
@ -80,6 +82,8 @@ private:
|
||||||
|
|
||||||
OwnPtr<DocumentData> create_document_data_for(const String& file);
|
OwnPtr<DocumentData> create_document_data_for(const String& file);
|
||||||
String document_path_from_include_path(const StringView& include_path) const;
|
String document_path_from_include_path(const StringView& include_path) const;
|
||||||
|
void update_declared_symbols(const DocumentData&);
|
||||||
|
GUI::AutocompleteProvider::DeclarationType type_of_declaration(const Declaration&);
|
||||||
|
|
||||||
HashMap<String, OwnPtr<DocumentData>> m_documents;
|
HashMap<String, OwnPtr<DocumentData>> m_documents;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,4 +2,5 @@ endpoint LanguageClient = 8002
|
||||||
{
|
{
|
||||||
AutoCompleteSuggestions(Vector<GUI::AutocompleteProvider::Entry> suggestions) =|
|
AutoCompleteSuggestions(Vector<GUI::AutocompleteProvider::Entry> suggestions) =|
|
||||||
DeclarationLocation(GUI::AutocompleteProvider::ProjectLocation location) =|
|
DeclarationLocation(GUI::AutocompleteProvider::ProjectLocation location) =|
|
||||||
|
DeclarationsInDocument(String filename, Vector<GUI::AutocompleteProvider::Declaration> declarations) =|
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,13 +137,19 @@ public:
|
||||||
virtual bool is_variable_declaration() const { return false; }
|
virtual bool is_variable_declaration() const { return false; }
|
||||||
virtual bool is_parameter() const { return false; }
|
virtual bool is_parameter() const { return false; }
|
||||||
virtual bool is_struct_or_class() const { return false; }
|
virtual bool is_struct_or_class() const { return false; }
|
||||||
|
virtual bool is_struct() const { return false; }
|
||||||
|
virtual bool is_class() const { return false; }
|
||||||
virtual bool is_function() const { return false; }
|
virtual bool is_function() const { return false; }
|
||||||
|
const StringView& name() const { return m_name; }
|
||||||
|
|
||||||
|
StringView m_name;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Declaration(ASTNode* parent, Optional<Position> start, Optional<Position> end, const String& filename)
|
Declaration(ASTNode* parent, Optional<Position> start, Optional<Position> end, const String& filename)
|
||||||
: Statement(parent, start, end, filename)
|
: Statement(parent, start, end, filename)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class InvalidDeclaration : public Declaration {
|
class InvalidDeclaration : public Declaration {
|
||||||
|
@ -163,7 +169,6 @@ public:
|
||||||
virtual const char* class_name() const override { return "FunctionDeclaration"; }
|
virtual const char* class_name() const override { return "FunctionDeclaration"; }
|
||||||
virtual void dump(size_t indent) const override;
|
virtual void dump(size_t indent) const override;
|
||||||
virtual bool is_function() const override { return true; }
|
virtual bool is_function() const override { return true; }
|
||||||
const StringView& name() const { return m_name; }
|
|
||||||
RefPtr<FunctionDefinition> definition() { return m_definition; }
|
RefPtr<FunctionDefinition> definition() { return m_definition; }
|
||||||
|
|
||||||
FunctionDeclaration(ASTNode* parent, Optional<Position> start, Optional<Position> end, const String& filename)
|
FunctionDeclaration(ASTNode* parent, Optional<Position> start, Optional<Position> end, const String& filename)
|
||||||
|
@ -173,7 +178,6 @@ public:
|
||||||
|
|
||||||
virtual NonnullRefPtrVector<Declaration> declarations() const override;
|
virtual NonnullRefPtrVector<Declaration> declarations() const override;
|
||||||
|
|
||||||
StringView m_name;
|
|
||||||
RefPtr<Type> m_return_type;
|
RefPtr<Type> m_return_type;
|
||||||
NonnullRefPtrVector<Parameter> m_parameters;
|
NonnullRefPtrVector<Parameter> m_parameters;
|
||||||
RefPtr<FunctionDefinition> m_definition;
|
RefPtr<FunctionDefinition> m_definition;
|
||||||
|
@ -184,7 +188,6 @@ public:
|
||||||
virtual ~VariableOrParameterDeclaration() override = default;
|
virtual ~VariableOrParameterDeclaration() override = default;
|
||||||
virtual bool is_variable_or_parameter_declaration() const override { return true; }
|
virtual bool is_variable_or_parameter_declaration() const override { return true; }
|
||||||
|
|
||||||
StringView m_name;
|
|
||||||
RefPtr<Type> m_type;
|
RefPtr<Type> m_type;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -492,6 +495,8 @@ public:
|
||||||
virtual const char* class_name() const override { return "StructOrClassDeclaration"; }
|
virtual const char* class_name() const override { return "StructOrClassDeclaration"; }
|
||||||
virtual void dump(size_t indent) const override;
|
virtual void dump(size_t indent) const override;
|
||||||
virtual bool is_struct_or_class() const override { return true; }
|
virtual bool is_struct_or_class() const override { return true; }
|
||||||
|
virtual bool is_struct() const override { return m_type == Type::Struct; }
|
||||||
|
virtual bool is_class() const override { return m_type == Type::Class; }
|
||||||
|
|
||||||
enum class Type {
|
enum class Type {
|
||||||
Struct,
|
Struct,
|
||||||
|
@ -505,7 +510,6 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
StructOrClassDeclaration::Type m_type;
|
StructOrClassDeclaration::Type m_type;
|
||||||
StringView m_name;
|
|
||||||
NonnullRefPtrVector<MemberDeclaration> m_members;
|
NonnullRefPtrVector<MemberDeclaration> m_members;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue