From e7e179212c5b1938fd00da62a1d5aca8441cf487 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 21 Nov 2020 22:12:37 +0300 Subject: [PATCH] HackStudio: Send an open file to language servers Language servers will now receive an open file instead of just its path. This means the language servers no longer need to access the filesystem to open the file themselves. The C++ language server now has no filesystem access whatsoever (although we might need to relax this in the future if it learns to complete #include paths), while the Shell language server can read /etc/passwd (it wants that in order to get the user's home directory) and browse (but not read!) the whole file system tree for completing paths. --- DevTools/HackStudio/Editor.cpp | 14 +++++++++++-- DevTools/HackStudio/LanguageClient.cpp | 4 ++-- DevTools/HackStudio/LanguageClient.h | 10 ++++------ .../LanguageClients/ServerConnections.h | 20 +++++++++---------- .../LanguageServers/Cpp/ClientConnection.cpp | 17 ++++------------ .../LanguageServers/Cpp/ClientConnection.h | 1 - .../HackStudio/LanguageServers/Cpp/main.cpp | 8 ++++++-- .../LanguageServers/LanguageServer.ipc | 4 ++-- .../Shell/ClientConnection.cpp | 17 ++++------------ .../LanguageServers/Shell/ClientConnection.h | 1 - .../HackStudio/LanguageServers/Shell/main.cpp | 16 +++++++++++++-- DevTools/HackStudio/main.cpp | 4 ++-- 12 files changed, 60 insertions(+), 56 deletions(-) diff --git a/DevTools/HackStudio/Editor.cpp b/DevTools/HackStudio/Editor.cpp index 4a081068e4..7a6972fb08 100644 --- a/DevTools/HackStudio/Editor.cpp +++ b/DevTools/HackStudio/Editor.cpp @@ -48,6 +48,7 @@ #include #include #include +#include // #define EDITOR_DEBUG @@ -480,8 +481,17 @@ void Editor::set_document(GUI::TextDocument& doc) set_syntax_highlighter(nullptr); } - if (m_language_client) - m_language_client->open_file(code_document.file_path().string()); + if (m_language_client) { + auto full_file_path = String::formatted("{}/{}", project().root_directory(), code_document.file_path()); + dbg() << "Opening " << full_file_path; + int fd = open(full_file_path.characters(), O_RDONLY | O_NOCTTY); + if (fd < 0) { + perror("open"); + return; + } + m_language_client->open_file(code_document.file_path().string(), fd); + close(fd); + } } Optional Editor::get_autocomplete_request_data() diff --git a/DevTools/HackStudio/LanguageClient.cpp b/DevTools/HackStudio/LanguageClient.cpp index f394dc674d..462f5b9791 100644 --- a/DevTools/HackStudio/LanguageClient.cpp +++ b/DevTools/HackStudio/LanguageClient.cpp @@ -36,9 +36,9 @@ void ServerConnection::handle(const Messages::LanguageClient::AutoCompleteSugges m_language_client->provide_autocomplete_suggestions(message.suggestions()); } -void LanguageClient::open_file(const String& path) +void LanguageClient::open_file(const String& path, int fd) { - m_connection.post_message(Messages::LanguageServer::FileOpened(path)); + m_connection.post_message(Messages::LanguageServer::FileOpened(path, fd)); } void LanguageClient::set_file_content(const String& path, const String& content) diff --git a/DevTools/HackStudio/LanguageClient.h b/DevTools/HackStudio/LanguageClient.h index 7d0f56d228..bd3298d7a8 100644 --- a/DevTools/HackStudio/LanguageClient.h +++ b/DevTools/HackStudio/LanguageClient.h @@ -43,9 +43,8 @@ class ServerConnection : public IPC::ServerConnection , public LanguageClientEndpoint { public: - ServerConnection(const StringView& socket, const StringView& project_path) + ServerConnection(const StringView& socket) : IPC::ServerConnection(*this, socket) - , m_project_path(project_path) { } @@ -61,7 +60,7 @@ public: virtual void handshake() override { - auto response = send_sync(m_project_path.string()); + auto response = send_sync(); set_my_client_id(response->client_id()); } @@ -73,7 +72,7 @@ public: if (auto instance = s_instances_for_projects.get(key); instance.has_value()) return *instance.value(); - auto connection = ConcreteType::construct(project_path); + auto connection = ConcreteType::construct(); connection->handshake(); s_instances_for_projects.set(key, *connection); return *connection; @@ -83,7 +82,6 @@ protected: virtual void handle(const Messages::LanguageClient::AutoCompleteSuggestions&) override; LanguageClient* m_language_client { nullptr }; - LexicalPath m_project_path; }; class LanguageClient { @@ -100,7 +98,7 @@ public: m_connection.detach(); } - virtual void open_file(const String& path); + virtual void open_file(const String& path, int fd); virtual void set_file_content(const String& path, const String& content); virtual void insert_text(const String& path, const String& text, size_t line, size_t column); virtual void remove_text(const String& path, size_t from_line, size_t from_column, size_t to_line, size_t to_column); diff --git a/DevTools/HackStudio/LanguageClients/ServerConnections.h b/DevTools/HackStudio/LanguageClients/ServerConnections.h index 89266e37ca..bcebdb419e 100644 --- a/DevTools/HackStudio/LanguageClients/ServerConnections.h +++ b/DevTools/HackStudio/LanguageClients/ServerConnections.h @@ -32,16 +32,16 @@ #include #include -#define LANGUAGE_CLIENT(namespace_, socket_name) \ - namespace namespace_ { \ - class ServerConnection : public HackStudio::ServerConnection { \ - C_OBJECT(ServerConnection) \ - private: \ - ServerConnection(const String& project_path) \ - : HackStudio::ServerConnection("/tmp/portal/language/" #socket_name, project_path) \ - { \ - } \ - }; \ +#define LANGUAGE_CLIENT(namespace_, socket_name) \ + namespace namespace_ { \ + class ServerConnection : public HackStudio::ServerConnection { \ + C_OBJECT(ServerConnection) \ + private: \ + ServerConnection() \ + : HackStudio::ServerConnection("/tmp/portal/language/" #socket_name) \ + { \ + } \ + }; \ } namespace LanguageClients { diff --git a/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.cpp b/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.cpp index e43fce6eef..d9dec9bdbb 100644 --- a/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.cpp +++ b/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.cpp @@ -53,12 +53,8 @@ void ClientConnection::die() exit(0); } -OwnPtr ClientConnection::handle(const Messages::LanguageServer::Greet& message) +OwnPtr ClientConnection::handle(const Messages::LanguageServer::Greet&) { - m_project_root = LexicalPath(message.project_root()); -#ifdef DEBUG_CPP_LANGUAGE_SERVER - dbgln("project_root: {}", m_project_root); -#endif return make(client_id()); } @@ -81,16 +77,11 @@ static DefaultDocumentClient s_default_document_client; void ClientConnection::handle(const Messages::LanguageServer::FileOpened& message) { - LexicalPath file_path(String::formatted("{}/{}", m_project_root, message.file_name())); -#ifdef DEBUG_CPP_LANGUAGE_SERVER - dbgln("FileOpened: {}", file_path); -#endif - - auto file = Core::File::construct(file_path.string()); - if (!file->open(Core::IODevice::ReadOnly)) { + auto file = Core::File::construct(this); + if (!file->open(message.file().fd(), Core::IODevice::ReadOnly, Core::File::ShouldCloseFileDescriptor::Yes)) { errno = file->error(); perror("open"); - dbgln("Failed to open project file: {}", file_path); + dbgln("Failed to open project file"); return; } auto content = file->read_all(); diff --git a/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.h b/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.h index 2df3519d92..d0a7b4558c 100644 --- a/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.h +++ b/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.h @@ -58,7 +58,6 @@ private: RefPtr document_for(const String& file_name); - LexicalPath m_project_root; HashMap> m_open_files; }; diff --git a/DevTools/HackStudio/LanguageServers/Cpp/main.cpp b/DevTools/HackStudio/LanguageServers/Cpp/main.cpp index 9d9ac3ee98..197fd91f27 100644 --- a/DevTools/HackStudio/LanguageServers/Cpp/main.cpp +++ b/DevTools/HackStudio/LanguageServers/Cpp/main.cpp @@ -36,16 +36,20 @@ int main(int, char**) { Core::EventLoop event_loop; - if (pledge("stdio unix rpath", nullptr) < 0) { + if (pledge("stdio unix recvfd", nullptr) < 0) { perror("pledge"); return 1; } auto socket = Core::LocalSocket::take_over_accepted_socket_from_system_server(); IPC::new_client_connection(socket.release_nonnull(), 1); - if (pledge("stdio rpath", nullptr) < 0) { + if (pledge("stdio recvfd", nullptr) < 0) { perror("pledge"); return 1; } + if (unveil(nullptr, nullptr) < 0) { + perror("unveil"); + return 1; + } return event_loop.exec(); } diff --git a/DevTools/HackStudio/LanguageServers/LanguageServer.ipc b/DevTools/HackStudio/LanguageServers/LanguageServer.ipc index 5301c91942..de16fa14ec 100644 --- a/DevTools/HackStudio/LanguageServers/LanguageServer.ipc +++ b/DevTools/HackStudio/LanguageServers/LanguageServer.ipc @@ -1,8 +1,8 @@ endpoint LanguageServer = 8001 { - Greet(String project_root) => (i32 client_id) + Greet() => (i32 client_id) - FileOpened(String file_name) =| + FileOpened(String file_name, IPC::File file) =| FileEditInsertText(String file_name, String text, i32 start_line, i32 start_column) =| FileEditRemoveText(String file_name, i32 start_line, i32 start_column, i32 end_line, i32 end_column) =| SetFileContent(String file_name, String content) =| diff --git a/DevTools/HackStudio/LanguageServers/Shell/ClientConnection.cpp b/DevTools/HackStudio/LanguageServers/Shell/ClientConnection.cpp index 823a36290f..3e32c0d7e9 100644 --- a/DevTools/HackStudio/LanguageServers/Shell/ClientConnection.cpp +++ b/DevTools/HackStudio/LanguageServers/Shell/ClientConnection.cpp @@ -53,12 +53,8 @@ void ClientConnection::die() exit(0); } -OwnPtr ClientConnection::handle(const Messages::LanguageServer::Greet& message) +OwnPtr ClientConnection::handle(const Messages::LanguageServer::Greet&) { - m_project_root = LexicalPath(message.project_root()); -#ifdef DEBUG_SH_LANGUAGE_SERVER - dbgln("project_root: {}", m_project_root); -#endif return make(client_id()); } @@ -81,16 +77,11 @@ static DefaultDocumentClient s_default_document_client; void ClientConnection::handle(const Messages::LanguageServer::FileOpened& message) { - LexicalPath file_path(String::formatted("{}/{}", m_project_root, message.file_name())); -#ifdef DEBUG_SH_LANGUAGE_SERVER - dbgln("FileOpened: {}", file_path); -#endif - - auto file = Core::File::construct(file_path.string()); - if (!file->open(Core::IODevice::ReadOnly)) { + auto file = Core::File::construct(this); + if (!file->open(message.file().fd(), Core::IODevice::ReadOnly, Core::File::ShouldCloseFileDescriptor::Yes)) { errno = file->error(); perror("open"); - dbgln("Failed to open project file: {}", file_path); + dbgln("Failed to open project file"); return; } auto content = file->read_all(); diff --git a/DevTools/HackStudio/LanguageServers/Shell/ClientConnection.h b/DevTools/HackStudio/LanguageServers/Shell/ClientConnection.h index 27f53857b3..bb7fc14bd9 100644 --- a/DevTools/HackStudio/LanguageServers/Shell/ClientConnection.h +++ b/DevTools/HackStudio/LanguageServers/Shell/ClientConnection.h @@ -59,7 +59,6 @@ private: RefPtr document_for(const String& file_name); - LexicalPath m_project_root; HashMap> m_open_files; AutoComplete m_autocomplete; diff --git a/DevTools/HackStudio/LanguageServers/Shell/main.cpp b/DevTools/HackStudio/LanguageServers/Shell/main.cpp index a5e1417e67..90e3f62271 100644 --- a/DevTools/HackStudio/LanguageServers/Shell/main.cpp +++ b/DevTools/HackStudio/LanguageServers/Shell/main.cpp @@ -36,16 +36,28 @@ int main(int, char**) { Core::EventLoop event_loop; - if (pledge("stdio unix rpath", nullptr) < 0) { + if (pledge("stdio unix rpath recvfd", nullptr) < 0) { perror("pledge"); return 1; } auto socket = Core::LocalSocket::take_over_accepted_socket_from_system_server(); IPC::new_client_connection(socket.release_nonnull(), 1); - if (pledge("stdio rpath", nullptr) < 0) { + if (pledge("stdio rpath recvfd", nullptr) < 0) { perror("pledge"); return 1; } + if (unveil("/etc/passwd", "r") < 0) { + perror("unveil"); + return 1; + } + if (unveil("/", "b") < 0) { + perror("unveil"); + return 1; + } + if (unveil(nullptr, nullptr) < 0) { + perror("unveil"); + return 1; + } return event_loop.exec(); } diff --git a/DevTools/HackStudio/main.cpp b/DevTools/HackStudio/main.cpp index 7dfab49f7c..7cad913aef 100644 --- a/DevTools/HackStudio/main.cpp +++ b/DevTools/HackStudio/main.cpp @@ -59,14 +59,14 @@ static void open_default_project_file(const String& project_path); int main(int argc, char** argv) { - if (pledge("stdio tty accept rpath cpath wpath shared_buffer proc exec unix fattr thread unix", nullptr) < 0) { + if (pledge("stdio tty accept rpath cpath wpath shared_buffer proc exec unix fattr thread unix sendfd", nullptr) < 0) { perror("pledge"); return 1; } auto app = GUI::Application::construct(argc, argv); - if (pledge("stdio tty accept rpath cpath wpath shared_buffer proc exec fattr thread unix", nullptr) < 0) { + if (pledge("stdio tty accept rpath cpath wpath shared_buffer proc exec fattr thread unix sendfd", nullptr) < 0) { perror("pledge"); return 1; }