Serenity Operating System
at master 174 lines 7.5 kB view raw
1/* 2 * Copyright (c) 2020, the SerenityOS developers. 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#pragma once 8 9#include "AutoCompleteResponse.h" 10#include <AK/Forward.h> 11#include <AK/LexicalPath.h> 12#include <AK/Types.h> 13#include <AK/WeakPtr.h> 14#include <AK/Weakable.h> 15#include <LibCore/ElapsedTimer.h> 16#include <LibCpp/Preprocessor.h> 17#include <LibIPC/ConnectionToServer.h> 18#include <LibSyntax/Language.h> 19 20#include <DevTools/HackStudio/LanguageServers/LanguageClientEndpoint.h> 21#include <DevTools/HackStudio/LanguageServers/LanguageServerEndpoint.h> 22 23namespace HackStudio { 24 25class LanguageClient; 26class ConnectionToServerWrapper; 27 28class ConnectionToServer 29 : public IPC::ConnectionToServer<LanguageClientEndpoint, LanguageServerEndpoint> 30 , public LanguageClientEndpoint { 31 friend class ConnectionToServerWrapper; 32 33public: 34 ConnectionToServer(NonnullOwnPtr<Core::LocalSocket> socket, DeprecatedString const& project_path) 35 : IPC::ConnectionToServer<LanguageClientEndpoint, LanguageServerEndpoint>(*this, move(socket)) 36 { 37 m_project_path = project_path; 38 async_greet(m_project_path); 39 } 40 41 WeakPtr<LanguageClient> language_client() { return m_current_language_client; } 42 DeprecatedString const& project_path() const { return m_project_path; } 43 44 virtual void die() override; 45 46 LanguageClient const* active_client() const { return !m_current_language_client ? nullptr : m_current_language_client.ptr(); } 47 48protected: 49 virtual void auto_complete_suggestions(Vector<CodeComprehension::AutocompleteResultEntry> const&) override; 50 virtual void declaration_location(CodeComprehension::ProjectLocation const&) override; 51 virtual void declarations_in_document(DeprecatedString const&, Vector<CodeComprehension::Declaration> const&) override; 52 virtual void todo_entries_in_document(DeprecatedString const&, Vector<CodeComprehension::TodoEntry> const&) override; 53 virtual void parameters_hint_result(Vector<DeprecatedString> const&, int index) override; 54 virtual void tokens_info_result(Vector<CodeComprehension::TokenInfo> const&) override; 55 void set_wrapper(ConnectionToServerWrapper& wrapper) { m_wrapper = &wrapper; } 56 57 DeprecatedString m_project_path; 58 WeakPtr<LanguageClient> m_current_language_client; 59 ConnectionToServerWrapper* m_wrapper { nullptr }; 60}; 61 62class ConnectionToServerWrapper { 63 AK_MAKE_NONCOPYABLE(ConnectionToServerWrapper); 64 65public: 66 explicit ConnectionToServerWrapper(DeprecatedString const& language_name, Function<NonnullRefPtr<ConnectionToServer>()> connection_creator); 67 ~ConnectionToServerWrapper() = default; 68 69 template<typename LanguageServerType> 70 static ConnectionToServerWrapper& get_or_create(DeprecatedString const& project_path); 71 72 Syntax::Language language() const { return m_language; } 73 ConnectionToServer* connection(); 74 void on_crash(); 75 void try_respawn_connection(); 76 77 void attach(LanguageClient& client); 78 void detach(); 79 void set_active_client(LanguageClient& client); 80 81private: 82 void create_connection(); 83 void show_crash_notification() const; 84 void show_frequent_crashes_notification() const; 85 86 Syntax::Language m_language; 87 Function<NonnullRefPtr<ConnectionToServer>()> m_connection_creator; 88 RefPtr<ConnectionToServer> m_connection; 89 90 Core::ElapsedTimer m_last_crash_timer; 91 bool m_respawn_allowed { true }; 92}; 93 94class ConnectionToServerInstances { 95public: 96 static void set_instance_for_language(DeprecatedString const& language_name, NonnullOwnPtr<ConnectionToServerWrapper>&& connection_wrapper); 97 static void remove_instance_for_language(DeprecatedString const& language_name); 98 99 static ConnectionToServerWrapper* get_instance_wrapper(DeprecatedString const& language_name); 100 101private: 102 static HashMap<DeprecatedString, NonnullOwnPtr<ConnectionToServerWrapper>> s_instance_for_language; 103}; 104 105class LanguageClient : public Weakable<LanguageClient> { 106public: 107 explicit LanguageClient(ConnectionToServerWrapper& connection_wrapper) 108 : m_connection_wrapper(connection_wrapper) 109 { 110 if (m_connection_wrapper.connection()) { 111 m_previous_client = m_connection_wrapper.connection()->language_client(); 112 VERIFY(m_previous_client.ptr() != this); 113 m_connection_wrapper.attach(*this); 114 } 115 } 116 117 virtual ~LanguageClient() 118 { 119 // m_connection_wrapper is nullified if the server crashes 120 if (m_connection_wrapper.connection()) 121 m_connection_wrapper.detach(); 122 123 VERIFY(m_previous_client.ptr() != this); 124 if (m_previous_client && m_connection_wrapper.connection()) 125 m_connection_wrapper.set_active_client(*m_previous_client); 126 } 127 128 Syntax::Language language() const { return m_connection_wrapper.language(); } 129 void set_active_client(); 130 bool is_active_client() const; 131 virtual void open_file(DeprecatedString const& path, int fd); 132 virtual void set_file_content(DeprecatedString const& path, DeprecatedString const& content); 133 virtual void insert_text(DeprecatedString const& path, DeprecatedString const& text, size_t line, size_t column); 134 virtual void remove_text(DeprecatedString const& path, size_t from_line, size_t from_column, size_t to_line, size_t to_column); 135 virtual void request_autocomplete(DeprecatedString const& path, size_t cursor_line, size_t cursor_column); 136 virtual void search_declaration(DeprecatedString const& path, size_t line, size_t column); 137 virtual void get_parameters_hint(DeprecatedString const& path, size_t line, size_t column); 138 virtual void get_tokens_info(DeprecatedString const& filename); 139 140 void provide_autocomplete_suggestions(Vector<CodeComprehension::AutocompleteResultEntry> const&) const; 141 void declaration_found(DeprecatedString const& file, size_t line, size_t column) const; 142 void parameters_hint_result(Vector<DeprecatedString> const& params, size_t argument_index) const; 143 144 // Callbacks that get called when the result of a language server query is ready 145 Function<void(Vector<CodeComprehension::AutocompleteResultEntry>)> on_autocomplete_suggestions; 146 Function<void(DeprecatedString const&, size_t, size_t)> on_declaration_found; 147 Function<void(Vector<DeprecatedString> const&, size_t)> on_function_parameters_hint_result; 148 Function<void(Vector<CodeComprehension::TokenInfo> const&)> on_tokens_info_result; 149 150private: 151 ConnectionToServerWrapper& m_connection_wrapper; 152 WeakPtr<LanguageClient> m_previous_client; 153}; 154 155template<typename ConnectionToServerT> 156static inline NonnullOwnPtr<LanguageClient> get_language_client(DeprecatedString const& project_path) 157{ 158 return make<LanguageClient>(ConnectionToServerWrapper::get_or_create<ConnectionToServerT>(project_path)); 159} 160 161template<typename LanguageServerType> 162ConnectionToServerWrapper& ConnectionToServerWrapper::get_or_create(DeprecatedString const& project_path) 163{ 164 auto* wrapper = ConnectionToServerInstances::get_instance_wrapper(LanguageServerType::language_name()); 165 if (wrapper) 166 return *wrapper; 167 168 auto connection_wrapper_ptr = make<ConnectionToServerWrapper>(LanguageServerType::language_name(), [project_path]() { return LanguageServerType::try_create(project_path).release_value_but_fixme_should_propagate_errors(); }); 169 auto& connection_wrapper = *connection_wrapper_ptr; 170 ConnectionToServerInstances::set_instance_for_language(LanguageServerType::language_name(), move(connection_wrapper_ptr)); 171 return connection_wrapper; 172} 173 174}