Serenity Operating System
at master 155 lines 5.8 kB view raw
1/* 2 * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com> 3 * Copyright (c) 2022, the SerenityOS developers. 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include "ConnectionFromClient.h" 9#include <AK/Debug.h> 10#include <AK/HashMap.h> 11#include <LibGUI/TextDocument.h> 12 13namespace LanguageServers { 14 15static HashMap<int, RefPtr<ConnectionFromClient>> s_connections; 16 17ConnectionFromClient::ConnectionFromClient(NonnullOwnPtr<Core::LocalSocket> socket) 18 : IPC::ConnectionFromClient<LanguageClientEndpoint, LanguageServerEndpoint>(*this, move(socket), 1) 19{ 20 s_connections.set(1, *this); 21} 22 23void ConnectionFromClient::die() 24{ 25 s_connections.remove(client_id()); 26 exit(0); 27} 28 29void ConnectionFromClient::greet(DeprecatedString const& project_root) 30{ 31 m_filedb.set_project_root(project_root); 32 if (unveil(project_root.characters(), "r") < 0) { 33 perror("unveil"); 34 exit(1); 35 } 36 if (unveil(nullptr, nullptr) < 0) { 37 perror("unveil"); 38 exit(1); 39 } 40} 41 42void ConnectionFromClient::file_opened(DeprecatedString const& filename, IPC::File const& file) 43{ 44 if (m_filedb.is_open(filename)) { 45 return; 46 } 47 m_filedb.add(filename, file.take_fd()); 48 m_autocomplete_engine->file_opened(filename); 49} 50 51void ConnectionFromClient::file_edit_insert_text(DeprecatedString const& filename, DeprecatedString const& text, i32 start_line, i32 start_column) 52{ 53 dbgln_if(LANGUAGE_SERVER_DEBUG, "InsertText for file: {}", filename); 54 dbgln_if(LANGUAGE_SERVER_DEBUG, "Text: {}", text); 55 dbgln_if(LANGUAGE_SERVER_DEBUG, "[{}:{}]", start_line, start_column); 56 m_filedb.on_file_edit_insert_text(filename, text, start_line, start_column); 57 m_autocomplete_engine->on_edit(filename); 58} 59 60void ConnectionFromClient::file_edit_remove_text(DeprecatedString const& filename, i32 start_line, i32 start_column, i32 end_line, i32 end_column) 61{ 62 dbgln_if(LANGUAGE_SERVER_DEBUG, "RemoveText for file: {}", filename); 63 dbgln_if(LANGUAGE_SERVER_DEBUG, "[{}:{} - {}:{}]", start_line, start_column, end_line, end_column); 64 m_filedb.on_file_edit_remove_text(filename, start_line, start_column, end_line, end_column); 65 m_autocomplete_engine->on_edit(filename); 66} 67 68void ConnectionFromClient::auto_complete_suggestions(CodeComprehension::ProjectLocation const& location) 69{ 70 dbgln_if(LANGUAGE_SERVER_DEBUG, "AutoCompleteSuggestions for: {} {}:{}", location.file, location.line, location.column); 71 72 auto document = m_filedb.get_document(location.file); 73 if (!document) { 74 dbgln("file {} has not been opened", location.file); 75 return; 76 } 77 78 GUI::TextPosition autocomplete_position = { (size_t)location.line, (size_t)max(location.column, location.column - 1) }; 79 Vector<CodeComprehension::AutocompleteResultEntry> suggestions = m_autocomplete_engine->get_suggestions(location.file, autocomplete_position); 80 async_auto_complete_suggestions(move(suggestions)); 81} 82 83void ConnectionFromClient::set_file_content(DeprecatedString const& filename, DeprecatedString const& content) 84{ 85 dbgln_if(LANGUAGE_SERVER_DEBUG, "SetFileContent: {}", filename); 86 auto document = m_filedb.get_document(filename); 87 if (!document) { 88 m_filedb.add(filename, content); 89 VERIFY(m_filedb.is_open(filename)); 90 } else { 91 document->set_text(content.view()); 92 } 93 VERIFY(m_filedb.is_open(filename)); 94 m_autocomplete_engine->on_edit(filename); 95} 96 97void ConnectionFromClient::find_declaration(CodeComprehension::ProjectLocation const& location) 98{ 99 dbgln_if(LANGUAGE_SERVER_DEBUG, "FindDeclaration: {} {}:{}", location.file, location.line, location.column); 100 auto document = m_filedb.get_document(location.file); 101 if (!document) { 102 dbgln("file {} has not been opened", location.file); 103 return; 104 } 105 106 GUI::TextPosition identifier_position = { (size_t)location.line, (size_t)location.column }; 107 auto decl_location = m_autocomplete_engine->find_declaration_of(location.file, identifier_position); 108 if (!decl_location.has_value()) { 109 dbgln("could not find declaration"); 110 return; 111 } 112 113 dbgln_if(LANGUAGE_SERVER_DEBUG, "declaration location: {} {}:{}", decl_location.value().file, decl_location.value().line, decl_location.value().column); 114 async_declaration_location(CodeComprehension::ProjectLocation { decl_location.value().file, decl_location.value().line, decl_location.value().column }); 115} 116 117void ConnectionFromClient::get_parameters_hint(CodeComprehension::ProjectLocation const& location) 118{ 119 dbgln_if(LANGUAGE_SERVER_DEBUG, "GetParametersHint: {} {}:{}", location.file, location.line, location.column); 120 auto document = m_filedb.get_document(location.file); 121 if (!document) { 122 dbgln("file {} has not been opened", location.file); 123 return; 124 } 125 126 GUI::TextPosition identifier_position = { (size_t)location.line, (size_t)location.column }; 127 auto params = m_autocomplete_engine->get_function_params_hint(location.file, identifier_position); 128 if (!params.has_value()) { 129 dbgln("could not get parameters hint"); 130 return; 131 } 132 133 dbgln_if(LANGUAGE_SERVER_DEBUG, "parameters hint:"); 134 for (auto& param : params->params) { 135 dbgln_if(LANGUAGE_SERVER_DEBUG, "{}", param); 136 } 137 dbgln_if(LANGUAGE_SERVER_DEBUG, "Parameter index: {}", params->current_index); 138 139 async_parameters_hint_result(params->params, params->current_index); 140} 141 142void ConnectionFromClient::get_tokens_info(DeprecatedString const& filename) 143{ 144 dbgln_if(LANGUAGE_SERVER_DEBUG, "GetTokenInfo: {}", filename); 145 auto document = m_filedb.get_document(filename); 146 if (!document) { 147 dbgln("file {} has not been opened", filename); 148 return; 149 } 150 151 auto tokens_info = m_autocomplete_engine->get_tokens_info(filename); 152 async_tokens_info_result(move(tokens_info)); 153} 154 155}