mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-26 17:40:27 +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
Notes:
sideshowbarker
2024-07-18 21:53:01 +09:00
Author: https://github.com/itamar8910 Commit: https://github.com/SerenityOS/serenity/commit/4b483071fb5 Pull-request: https://github.com/SerenityOS/serenity/pull/5543 Issue: https://github.com/SerenityOS/serenity/issues/5478
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…
Reference in a new issue