mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 19:42:43 +00:00 
			
		
		
		
	LanguageServers: Add ProjectLoaction, Declaration types and use in IPC
With this we can avoid passing (name, line, column) tuples in many different places.
This commit is contained in:
		
							parent
							
								
									daf18e7777
								
							
						
					
					
						commit
						4b483071fb
					
				
					 10 changed files with 93 additions and 33 deletions
				
			
		|  | @ -64,4 +64,51 @@ inline bool decode(IPC::Decoder& decoder, GUI::AutocompleteProvider::Entry& resp | |||
|     return ok; | ||||
| } | ||||
| 
 | ||||
| template<> | ||||
| inline bool encode(Encoder& encoder, const GUI::AutocompleteProvider::ProjectLocation& location) | ||||
| { | ||||
|     encoder << location.file; | ||||
|     encoder << (u64)location.line; | ||||
|     encoder << (u64)location.column; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| template<> | ||||
| inline bool decode(Decoder& decoder, GUI::AutocompleteProvider::ProjectLocation& location) | ||||
| { | ||||
|     u64 line = 0; | ||||
|     u64 column = 0; | ||||
|     if (!decoder.decode(location.file)) | ||||
|         return false; | ||||
|     if (!decoder.decode(line)) | ||||
|         return false; | ||||
|     if (!decoder.decode(column)) | ||||
|         return false; | ||||
| 
 | ||||
|     location.line = line; | ||||
|     location.column = column; | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| template<> | ||||
| inline bool encode(Encoder& encoder, const GUI::AutocompleteProvider::Declaration& declaration) | ||||
| { | ||||
|     encoder << declaration.name; | ||||
|     if (!encode(encoder, declaration.position)) | ||||
|         return false; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| template<> | ||||
| inline bool decode(Decoder& decoder, GUI::AutocompleteProvider::Declaration& declaration) | ||||
| { | ||||
|     if (!decoder.decode(declaration.name)) | ||||
|         return false; | ||||
| 
 | ||||
|     if (!decode(decoder, declaration.position)) | ||||
|         return false; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -40,13 +40,19 @@ void ServerConnection::handle(const Messages::LanguageClient::AutoCompleteSugges | |||
|     } | ||||
|     m_language_client->provide_autocomplete_suggestions(message.suggestions()); | ||||
| } | ||||
| 
 | ||||
| void ServerConnection::handle(const Messages::LanguageClient::DeclarationLocation& message) | ||||
| { | ||||
|     if (!m_language_client) { | ||||
|         dbgln("Language Server connection has no attached language client"); | ||||
|         return; | ||||
|     } | ||||
|     m_language_client->declaration_found(message.file_name(), message.line(), message.column()); | ||||
|     m_language_client->declaration_found(message.location().file, message.location().line, message.location().column); | ||||
| } | ||||
| 
 | ||||
| void ServerConnection::handle(const Messages::LanguageClient::DeclarationList& message) | ||||
| { | ||||
|     (void)message; | ||||
| } | ||||
| 
 | ||||
| void ServerConnection::die() | ||||
|  | @ -90,7 +96,7 @@ void LanguageClient::request_autocomplete(const String& path, size_t cursor_line | |||
|     if (!m_server_connection) | ||||
|         return; | ||||
|     set_active_client(); | ||||
|     m_server_connection->post_message(Messages::LanguageServer::AutoCompleteSuggestions(path, cursor_line, cursor_column)); | ||||
|     m_server_connection->post_message(Messages::LanguageServer::AutoCompleteSuggestions(GUI::AutocompleteProvider::ProjectLocation { path, cursor_line, cursor_column })); | ||||
| } | ||||
| 
 | ||||
| void LanguageClient::provide_autocomplete_suggestions(const Vector<GUI::AutocompleteProvider::Entry>& suggestions) | ||||
|  | @ -158,7 +164,7 @@ void LanguageClient::search_declaration(const String& path, size_t line, size_t | |||
|     if (!m_server_connection) | ||||
|         return; | ||||
|     set_active_client(); | ||||
|     m_server_connection->post_message(Messages::LanguageServer::FindDeclaration(path, line, column)); | ||||
|     m_server_connection->post_message(Messages::LanguageServer::FindDeclaration(GUI::AutocompleteProvider::ProjectLocation { path, line, column })); | ||||
| } | ||||
| 
 | ||||
| void LanguageClient::declaration_found(const String& file, size_t line, size_t column) | ||||
|  |  | |||
|  | @ -28,6 +28,7 @@ | |||
| 
 | ||||
| #include "FileDB.h" | ||||
| #include <DevTools/HackStudio/AutoCompleteResponse.h> | ||||
| #include <LibGUI/AutocompleteProvider.h> | ||||
| #include <LibGUI/TextPosition.h> | ||||
| 
 | ||||
| class AutoCompleteEngine { | ||||
|  | @ -41,12 +42,7 @@ public: | |||
|     virtual void on_edit([[maybe_unused]] const String& file) {}; | ||||
|     virtual void file_opened([[maybe_unused]] const String& file) {}; | ||||
| 
 | ||||
|     struct ProjectPosition { | ||||
|         String file; | ||||
|         size_t line; | ||||
|         size_t column; | ||||
|     }; | ||||
|     virtual Optional<ProjectPosition> find_declaration_of(const String&, const GUI::TextPosition&) { return {}; }; | ||||
|     virtual Optional<GUI::AutocompleteProvider::ProjectLocation> find_declaration_of(const String&, const GUI::TextPosition&) { return {}; }; | ||||
| 
 | ||||
| protected: | ||||
|     const FileDB& filedb() const { return m_filedb; } | ||||
|  |  | |||
|  | @ -100,17 +100,17 @@ void ClientConnection::handle(const Messages::LanguageServer::FileEditRemoveText | |||
| void ClientConnection::handle(const Messages::LanguageServer::AutoCompleteSuggestions& message) | ||||
| { | ||||
| #if CPP_LANGUAGE_SERVER_DEBUG | ||||
|     dbgln("AutoCompleteSuggestions for: {} {}:{}", message.file_name(), message.cursor_line(), message.cursor_column()); | ||||
|     dbgln("AutoCompleteSuggestions for: {} {}:{}", message.location().file, message.location().line, message.location().column); | ||||
| #endif | ||||
| 
 | ||||
|     auto document = m_filedb.get(message.file_name()); | ||||
|     auto document = m_filedb.get(message.location().file); | ||||
|     if (!document) { | ||||
|         dbgln("file {} has not been opened", message.file_name()); | ||||
|         dbgln("file {} has not been opened", message.location().file); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     GUI::TextPosition autocomplete_position = { (size_t)message.cursor_line(), (size_t)max(message.cursor_column(), message.cursor_column() - 1) }; | ||||
|     Vector<GUI::AutocompleteProvider::Entry> suggestions = m_autocomplete_engine->get_suggestions(message.file_name(), autocomplete_position); | ||||
|     GUI::TextPosition autocomplete_position = { (size_t)message.location().line, (size_t)max(message.location().column, message.location().column - 1) }; | ||||
|     Vector<GUI::AutocompleteProvider::Entry> suggestions = m_autocomplete_engine->get_suggestions(message.location().file, autocomplete_position); | ||||
|     post_message(Messages::LanguageClient::AutoCompleteSuggestions(move(suggestions))); | ||||
| } | ||||
| 
 | ||||
|  | @ -139,21 +139,21 @@ void ClientConnection::handle(const Messages::LanguageServer::SetAutoCompleteMod | |||
| 
 | ||||
| void ClientConnection::handle(const Messages::LanguageServer::FindDeclaration& message) | ||||
| { | ||||
|     dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "FindDeclaration: {} {}:{}", message.file_name(), message.line(), message.column()); | ||||
|     auto document = m_filedb.get(message.file_name()); | ||||
|     dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "FindDeclaration: {} {}:{}", message.location().file, message.location().line, message.location().column); | ||||
|     auto document = m_filedb.get(message.location().file); | ||||
|     if (!document) { | ||||
|         dbgln("file {} has not been opened", message.file_name()); | ||||
|         dbgln("file {} has not been opened", message.location().file); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     GUI::TextPosition identifier_position = { (size_t)message.line(), (size_t)message.column() }; | ||||
|     auto location = m_autocomplete_engine->find_declaration_of(message.file_name(), identifier_position); | ||||
|     GUI::TextPosition identifier_position = { (size_t)message.location().line, (size_t)message.location().column }; | ||||
|     auto location = m_autocomplete_engine->find_declaration_of(message.location().file, identifier_position); | ||||
|     if (!location.has_value()) { | ||||
|         dbgln("could not find declaration"); | ||||
|         return; | ||||
|     } | ||||
|     dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "declaration location: {} {}:{}", location.value().file, location.value().line, location.value().column); | ||||
|     post_message(Messages::LanguageClient::DeclarationLocation(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 })); | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -317,7 +317,7 @@ void ParserAutoComplete::file_opened([[maybe_unused]] const String& file) | |||
|     set_document_data(file, create_document_data_for(file)); | ||||
| } | ||||
| 
 | ||||
| Optional<AutoCompleteEngine::ProjectPosition> ParserAutoComplete::find_declaration_of(const String& file_name, const GUI::TextPosition& identifier_position) | ||||
| Optional<GUI::AutocompleteProvider::ProjectLocation> ParserAutoComplete::find_declaration_of(const String& file_name, const GUI::TextPosition& identifier_position) | ||||
| { | ||||
|     const auto& document = get_or_create_document_data(file_name); | ||||
|     auto node = document.parser.node_at(Cpp::Position { identifier_position.line(), identifier_position.column() }); | ||||
|  | @ -329,7 +329,7 @@ Optional<AutoCompleteEngine::ProjectPosition> ParserAutoComplete::find_declarati | |||
|     if (!decl) | ||||
|         return {}; | ||||
| 
 | ||||
|     return ProjectPosition { decl->filename(), decl->start().line, decl->start().column }; | ||||
|     return GUI::AutocompleteProvider::ProjectLocation { decl->filename(), decl->start().line, decl->start().column }; | ||||
| } | ||||
| 
 | ||||
| RefPtr<Declaration> ParserAutoComplete::find_declaration_of(const DocumentData& document_data, const ASTNode& node) const | ||||
|  |  | |||
|  | @ -47,7 +47,7 @@ public: | |||
|     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 file_opened([[maybe_unused]] const String& file) override; | ||||
|     virtual Optional<ProjectPosition> find_declaration_of(const String& file_name, const GUI::TextPosition& identifier_position) override; | ||||
|     virtual Optional<GUI::AutocompleteProvider::ProjectLocation> find_declaration_of(const String& file_name, const GUI::TextPosition& identifier_position) override; | ||||
| 
 | ||||
| private: | ||||
|     struct DocumentData { | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| endpoint LanguageClient = 8002 | ||||
| { | ||||
|     AutoCompleteSuggestions(Vector<GUI::AutocompleteProvider::Entry> suggestions) =| | ||||
|     DeclarationLocation(String file_name, i32 line, i32 column) =| | ||||
|     DeclarationLocation(GUI::AutocompleteProvider::ProjectLocation location) =| | ||||
| } | ||||
|  |  | |||
|  | @ -7,8 +7,7 @@ endpoint LanguageServer = 8001 | |||
|     FileEditRemoveText(String file_name, i32 start_line, i32 start_column, i32 end_line, i32 end_column) =| | ||||
|     SetFileContent(String file_name, String content) =| | ||||
| 
 | ||||
|     AutoCompleteSuggestions(String file_name, i32 cursor_line, i32 cursor_column) =| | ||||
|     AutoCompleteSuggestions(GUI::AutocompleteProvider::ProjectLocation location) =| | ||||
|     SetAutoCompleteMode(String mode) =| | ||||
|     FindDeclaration(String file_name, i32 line, i32 column) =| | ||||
| 
 | ||||
|     FindDeclaration(GUI::AutocompleteProvider::ProjectLocation location) =| | ||||
| } | ||||
|  |  | |||
|  | @ -135,23 +135,23 @@ void ClientConnection::handle(const Messages::LanguageServer::FileEditRemoveText | |||
| void ClientConnection::handle(const Messages::LanguageServer::AutoCompleteSuggestions& message) | ||||
| { | ||||
| #if SH_LANGUAGE_SERVER_DEBUG | ||||
|     dbgln("AutoCompleteSuggestions for: {} {}:{}", message.file_name(), message.cursor_line(), message.cursor_column()); | ||||
|     dbgln("AutoCompleteSuggestions for: {} {}:{}", message.location().file, message.location().line, message.location().column); | ||||
| #endif | ||||
| 
 | ||||
|     auto document = document_for(message.file_name()); | ||||
|     auto document = document_for(message.location().file); | ||||
|     if (!document) { | ||||
|         dbgln("file {} has not been opened", message.file_name()); | ||||
|         dbgln("file {} has not been opened", message.location().file); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto& lines = document->lines(); | ||||
|     size_t offset = 0; | ||||
| 
 | ||||
|     if (message.cursor_line() > 0) { | ||||
|         for (auto i = 0; i < message.cursor_line(); ++i) | ||||
|     if (message.location().line > 0) { | ||||
|         for (size_t i = 0; i < message.location().line; ++i) | ||||
|             offset += lines[i].length() + 1; | ||||
|     } | ||||
|     offset += message.cursor_column(); | ||||
|     offset += message.location().column; | ||||
| 
 | ||||
|     auto suggestions = m_autocomplete.get_suggestions(document->text(), offset); | ||||
|     post_message(Messages::LanguageClient::AutoCompleteSuggestions(move(suggestions))); | ||||
|  |  | |||
|  | @ -29,6 +29,7 @@ | |||
| #include <LibGUI/Forward.h> | ||||
| #include <LibGUI/TextEditor.h> | ||||
| #include <LibGUI/Window.h> | ||||
| #include <LibIPC/Decoder.h> | ||||
| 
 | ||||
| namespace GUI { | ||||
| 
 | ||||
|  | @ -55,6 +56,17 @@ public: | |||
|         Language language { Language::Unspecified }; | ||||
|     }; | ||||
| 
 | ||||
|     struct ProjectLocation { | ||||
|         String file; | ||||
|         size_t line { 0 }; | ||||
|         size_t column { 0 }; | ||||
|     }; | ||||
| 
 | ||||
|     struct Declaration { | ||||
|         String name; | ||||
|         ProjectLocation position; | ||||
|     }; | ||||
| 
 | ||||
|     virtual void provide_completions(Function<void(Vector<Entry>)>) = 0; | ||||
| 
 | ||||
|     void attach(TextEditor& editor) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Itamar
						Itamar