mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 17:52:45 +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)) | ||||
|         return false; | ||||
|     u32 type; | ||||
|     if (!decoder.decode( type)) | ||||
|     if (!decoder.decode(type)) | ||||
|         return false; | ||||
| 
 | ||||
|     declaration.type = static_cast<GUI::AutocompleteProvider::DeclarationType>(type); | ||||
|  |  | |||
|  | @ -91,6 +91,7 @@ public: | |||
| protected: | ||||
|     virtual void handle(const Messages::LanguageClient::AutoCompleteSuggestions&) override; | ||||
|     virtual void handle(const Messages::LanguageClient::DeclarationLocation&) override; | ||||
|     virtual void handle(const Messages::LanguageClient::DeclarationsInDocument&) override; | ||||
| 
 | ||||
|     String m_project_path; | ||||
|     WeakPtr<LanguageClient> m_language_client; | ||||
|  |  | |||
|  | @ -26,11 +26,20 @@ | |||
| 
 | ||||
| #include "AutoCompleteEngine.h" | ||||
| 
 | ||||
| AutoCompleteEngine::AutoCompleteEngine(const FileDB& filedb) | ||||
|     : m_filedb(filedb) | ||||
| namespace LanguageServers::Cpp { | ||||
| 
 | ||||
| AutoCompleteEngine::AutoCompleteEngine(ClientConnection& connection, const FileDB& filedb) | ||||
|     : m_connection(connection) | ||||
|     , m_filedb(filedb) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| 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/TextPosition.h> | ||||
| 
 | ||||
| namespace LanguageServers::Cpp { | ||||
| 
 | ||||
| class ClientConnection; | ||||
| 
 | ||||
| class AutoCompleteEngine { | ||||
| public: | ||||
|     AutoCompleteEngine(const FileDB& filedb); | ||||
|     AutoCompleteEngine(ClientConnection&, const FileDB& filedb); | ||||
|     virtual ~AutoCompleteEngine(); | ||||
| 
 | ||||
|     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 {}; }; | ||||
| 
 | ||||
| public: | ||||
|     Function<void(ClientConnection&, String, Vector<GUI::AutocompleteProvider::Declaration>)> set_declarations_of_document_callback; | ||||
| 
 | ||||
| protected: | ||||
|     const FileDB& filedb() const { return m_filedb; } | ||||
|     void set_declarations_of_document(const String&, Vector<GUI::AutocompleteProvider::Declaration>&&); | ||||
| 
 | ||||
| private: | ||||
|     ClientConnection& m_connection; | ||||
|     const FileDB& m_filedb; | ||||
| }; | ||||
| } | ||||
|  |  | |||
|  | @ -40,7 +40,8 @@ ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> socket, int | |||
|     : IPC::ClientConnection<LanguageClientEndpoint, LanguageServerEndpoint>(*this, move(socket), client_id) | ||||
| { | ||||
|     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() | ||||
|  | @ -132,9 +133,9 @@ void ClientConnection::handle(const Messages::LanguageServer::SetAutoCompleteMod | |||
|     dbgln("SetAutoCompleteMode: {}", message.mode()); | ||||
| #endif | ||||
|     if (message.mode() == "Parser") | ||||
|         m_autocomplete_engine = make<ParserAutoComplete>(m_filedb); | ||||
|         m_autocomplete_engine = make<ParserAutoComplete>(*this, m_filedb); | ||||
|     else | ||||
|         m_autocomplete_engine = make<LexerAutoComplete>(m_filedb); | ||||
|         m_autocomplete_engine = make<LexerAutoComplete>(*this, m_filedb); | ||||
| } | ||||
| 
 | ||||
| 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 })); | ||||
| } | ||||
| 
 | ||||
| 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::FindDeclaration&) override; | ||||
| 
 | ||||
|     static void set_declarations_of_document_callback(ClientConnection&, const String&, Vector<GUI::AutocompleteProvider::Declaration>&&); | ||||
| 
 | ||||
|     FileDB m_filedb; | ||||
|     OwnPtr<AutoCompleteEngine> m_autocomplete_engine; | ||||
| }; | ||||
|  |  | |||
|  | @ -31,8 +31,8 @@ | |||
| 
 | ||||
| namespace LanguageServers::Cpp { | ||||
| 
 | ||||
| LexerAutoComplete::LexerAutoComplete(const FileDB& filedb) | ||||
|     : AutoCompleteEngine(filedb) | ||||
| LexerAutoComplete::LexerAutoComplete(ClientConnection& connection, const FileDB& filedb) | ||||
|     : AutoCompleteEngine(connection, filedb) | ||||
| { | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -39,7 +39,7 @@ using namespace ::Cpp; | |||
| 
 | ||||
| class LexerAutoComplete : public AutoCompleteEngine { | ||||
| 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; | ||||
| 
 | ||||
|  |  | |||
|  | @ -27,6 +27,7 @@ | |||
| #include "ParserAutoComplete.h" | ||||
| #include <AK/Assertions.h> | ||||
| #include <AK/HashTable.h> | ||||
| #include <DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.h> | ||||
| #include <LibCpp/AST.h> | ||||
| #include <LibCpp/Lexer.h> | ||||
| #include <LibCpp/Parser.h> | ||||
|  | @ -35,8 +36,8 @@ | |||
| 
 | ||||
| namespace LanguageServers::Cpp { | ||||
| 
 | ||||
| ParserAutoComplete::ParserAutoComplete(const FileDB& filedb) | ||||
|     : AutoCompleteEngine(filedb) | ||||
| ParserAutoComplete::ParserAutoComplete(ClientConnection& connection, const FileDB& filedb) | ||||
|     : AutoCompleteEngine(connection, filedb) | ||||
| { | ||||
| } | ||||
| 
 | ||||
|  | @ -71,6 +72,9 @@ OwnPtr<ParserAutoComplete::DocumentData> ParserAutoComplete::create_document_dat | |||
| #ifdef CPP_LANGUAGE_SERVER_DEBUG | ||||
|     root->dump(0); | ||||
| #endif | ||||
| 
 | ||||
|     update_declared_symbols(*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)); | ||||
| } | ||||
| 
 | ||||
| ParserAutoComplete::DocumentData::DocumentData(String&& _text, const String& filename) | ||||
|     : text(move(_text)) | ||||
| ParserAutoComplete::DocumentData::DocumentData(String&& _text, const String& _filename) | ||||
|     : filename(_filename) | ||||
|     , text(move(_text)) | ||||
|     , preprocessor(text.view()) | ||||
|     , parser(preprocessor.process().view(), filename) | ||||
| { | ||||
|  | @ -360,4 +365,26 @@ RefPtr<Declaration> ParserAutoComplete::find_declaration_of(const DocumentData& | |||
|     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 "FileDB.h" | ||||
| #include <AK/Function.h> | ||||
| #include <AK/String.h> | ||||
| #include <AK/Vector.h> | ||||
| #include <DevTools/HackStudio/AutoCompleteResponse.h> | ||||
|  | @ -42,7 +43,7 @@ using namespace ::Cpp; | |||
| 
 | ||||
| class ParserAutoComplete : public AutoCompleteEngine { | ||||
| 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 void on_edit(const String& file) override; | ||||
|  | @ -52,6 +53,7 @@ public: | |||
| private: | ||||
|     struct DocumentData { | ||||
|         DocumentData(String&& text, const String& filename); | ||||
|         String filename; | ||||
|         String text; | ||||
|         Preprocessor preprocessor; | ||||
|         Parser parser; | ||||
|  | @ -80,6 +82,8 @@ private: | |||
| 
 | ||||
|     OwnPtr<DocumentData> create_document_data_for(const String& file); | ||||
|     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; | ||||
| }; | ||||
|  |  | |||
|  | @ -2,4 +2,5 @@ endpoint LanguageClient = 8002 | |||
| { | ||||
|     AutoCompleteSuggestions(Vector<GUI::AutocompleteProvider::Entry> suggestions) =| | ||||
|     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_parameter() 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; } | ||||
|     const StringView& name() const { return m_name; } | ||||
| 
 | ||||
|     StringView m_name; | ||||
| 
 | ||||
| protected: | ||||
|     Declaration(ASTNode* parent, Optional<Position> start, Optional<Position> end, const String& filename) | ||||
|         : Statement(parent, start, end, filename) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| class InvalidDeclaration : public Declaration { | ||||
|  | @ -163,7 +169,6 @@ public: | |||
|     virtual const char* class_name() const override { return "FunctionDeclaration"; } | ||||
|     virtual void dump(size_t indent) const override; | ||||
|     virtual bool is_function() const override { return true; } | ||||
|     const StringView& name() const { return m_name; } | ||||
|     RefPtr<FunctionDefinition> definition() { return m_definition; } | ||||
| 
 | ||||
|     FunctionDeclaration(ASTNode* parent, Optional<Position> start, Optional<Position> end, const String& filename) | ||||
|  | @ -173,7 +178,6 @@ public: | |||
| 
 | ||||
|     virtual NonnullRefPtrVector<Declaration> declarations() const override; | ||||
| 
 | ||||
|     StringView m_name; | ||||
|     RefPtr<Type> m_return_type; | ||||
|     NonnullRefPtrVector<Parameter> m_parameters; | ||||
|     RefPtr<FunctionDefinition> m_definition; | ||||
|  | @ -184,7 +188,6 @@ public: | |||
|     virtual ~VariableOrParameterDeclaration() override = default; | ||||
|     virtual bool is_variable_or_parameter_declaration() const override { return true; } | ||||
| 
 | ||||
|     StringView m_name; | ||||
|     RefPtr<Type> m_type; | ||||
| 
 | ||||
| protected: | ||||
|  | @ -492,6 +495,8 @@ public: | |||
|     virtual const char* class_name() const override { return "StructOrClassDeclaration"; } | ||||
|     virtual void dump(size_t indent) const override; | ||||
|     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 { | ||||
|         Struct, | ||||
|  | @ -505,7 +510,6 @@ public: | |||
|     } | ||||
| 
 | ||||
|     StructOrClassDeclaration::Type m_type; | ||||
|     StringView m_name; | ||||
|     NonnullRefPtrVector<MemberDeclaration> m_members; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Itamar
						Itamar