From fa18010477821f114953015677daa789580a4683 Mon Sep 17 00:00:00 2001 From: Itamar Date: Sat, 23 Jan 2021 16:55:19 +0200 Subject: [PATCH] HackStudio: Integate with C++ parser-based autocomplete By default, C++ auto completion will still be performed by the lexer-based logic. However, the parser-based logic can be switched on via the menubar. --- Base/home/anon/Source/little/main.cpp | 8 +++++- Meta/CMake/all_the_debug_macros.cmake | 3 +++ .../DevTools/HackStudio/HackStudioWidget.cpp | 9 +++++++ .../DevTools/HackStudio/HackStudioWidget.h | 1 + .../DevTools/HackStudio/LanguageClient.cpp | 6 +++++ Userland/DevTools/HackStudio/LanguageClient.h | 1 + .../LanguageServers/Cpp/CMakeLists.txt | 3 ++- .../LanguageServers/Cpp/ClientConnection.cpp | 25 +++++++++++++++++-- .../LanguageServers/Cpp/ClientConnection.h | 8 ++++++ ...AutoComplete.cpp => LexerAutoComplete.cpp} | 10 ++++---- .../{AutoComplete.h => LexerAutoComplete.h} | 4 +-- .../LanguageServers/LanguageServer.ipc | 1 + .../LanguageServers/Shell/ClientConnection.h | 1 + .../Libraries/LibGUI/AutocompleteProvider.cpp | 1 + 14 files changed, 70 insertions(+), 11 deletions(-) rename Userland/DevTools/HackStudio/LanguageServers/Cpp/{AutoComplete.cpp => LexerAutoComplete.cpp} (85%) rename Userland/DevTools/HackStudio/LanguageServers/Cpp/{AutoComplete.h => LexerAutoComplete.h} (97%) diff --git a/Base/home/anon/Source/little/main.cpp b/Base/home/anon/Source/little/main.cpp index 2fa2d31126..55b8bed3c6 100644 --- a/Base/home/anon/Source/little/main.cpp +++ b/Base/home/anon/Source/little/main.cpp @@ -1,6 +1,6 @@ +#include "other.h" #include #include -#include "other.h" enum TestEnum { ValueOne, @@ -13,11 +13,17 @@ struct MyStruct { TestEnum test_value { ValueOne }; }; +struct Container { + MyStruct inner; + int index; +}; + int main(int, char**) { MyStruct my_struct; my_struct.status = !my_struct.status; printf("my_struct.x is %d\n", my_struct.x); + Container container; for (int i = 0; i < 3; ++i) { // This is a comment :^) func(); diff --git a/Meta/CMake/all_the_debug_macros.cmake b/Meta/CMake/all_the_debug_macros.cmake index 2d93233773..339a9baae4 100644 --- a/Meta/CMake/all_the_debug_macros.cmake +++ b/Meta/CMake/all_the_debug_macros.cmake @@ -160,6 +160,9 @@ set(VOLATILE_PAGE_RANGES_DEBUG ON) set(WSMESSAGELOOP_DEBUG ON) set(GPT_DEBUG ON) set(CPP_DEBUG ON) +set(DEBUG_SPAM ON) +set(DEBUG_CPP_LANGUAGE_SERVER ON) +set(DEBUG_AUTOCOMPLETE ON) # False positive: DEBUG is a flag but it works differently. # set(DEBUG ON) diff --git a/Userland/DevTools/HackStudio/HackStudioWidget.cpp b/Userland/DevTools/HackStudio/HackStudioWidget.cpp index 7ef0eb33d2..15dfd5a7d9 100644 --- a/Userland/DevTools/HackStudio/HackStudioWidget.cpp +++ b/Userland/DevTools/HackStudio/HackStudioWidget.cpp @@ -841,6 +841,7 @@ void HackStudioWidget::create_project_menubar(GUI::MenuBar& menubar) { auto& project_menu = menubar.add_menu("Project"); project_menu.add_action(*m_new_action); + project_menu.add_action(*create_set_autocomplete_mode_action()); } void HackStudioWidget::create_edit_menubar(GUI::MenuBar& menubar) @@ -919,6 +920,14 @@ NonnullRefPtr HackStudioWidget::create_stop_action() return action; } +NonnullRefPtr HackStudioWidget::create_set_autocomplete_mode_action() +{ + auto action = GUI::Action::create_checkable("AutoComplete C++ with Parser", [this](auto& action) { + get_language_client(project().root_path())->set_autocomplete_mode(action.is_checked() ? "Parser" : "Lexer"); + }); + return action; +} + void HackStudioWidget::initialize_menubar(GUI::MenuBar& menubar) { create_app_menubar(menubar); diff --git a/Userland/DevTools/HackStudio/HackStudioWidget.h b/Userland/DevTools/HackStudio/HackStudioWidget.h index 29ef3701e4..d35ec85284 100644 --- a/Userland/DevTools/HackStudio/HackStudioWidget.h +++ b/Userland/DevTools/HackStudio/HackStudioWidget.h @@ -94,6 +94,7 @@ private: NonnullRefPtr create_build_action(); NonnullRefPtr create_run_action(); NonnullRefPtr create_stop_action(); + NonnullRefPtr create_set_autocomplete_mode_action(); void add_new_editor(GUI::Widget& parent); NonnullRefPtr get_editor_of_file(const String& file_name); diff --git a/Userland/DevTools/HackStudio/LanguageClient.cpp b/Userland/DevTools/HackStudio/LanguageClient.cpp index e02b2c98cf..98341a046f 100644 --- a/Userland/DevTools/HackStudio/LanguageClient.cpp +++ b/Userland/DevTools/HackStudio/LanguageClient.cpp @@ -25,6 +25,7 @@ */ #include "LanguageClient.h" +#include "DevTools/HackStudio/LanguageServers/LanguageServerEndpoint.h" #include #include @@ -72,4 +73,9 @@ void LanguageClient::provide_autocomplete_suggestions(const Vector&); diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/CMakeLists.txt b/Userland/DevTools/HackStudio/LanguageServers/Cpp/CMakeLists.txt index de9569d8ca..7d34577447 100644 --- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/CMakeLists.txt +++ b/Userland/DevTools/HackStudio/LanguageServers/Cpp/CMakeLists.txt @@ -1,7 +1,8 @@ set(SOURCES ClientConnection.cpp main.cpp - AutoComplete.cpp + LexerAutoComplete.cpp + ParserAutoComplete.cpp ) set(GENERATED_SOURCES diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.cpp b/Userland/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.cpp index 5881dbbeee..c3cdedeef4 100644 --- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.cpp +++ b/Userland/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.cpp @@ -25,7 +25,8 @@ */ #include "ClientConnection.h" -#include "AutoComplete.h" +#include "LexerAutoComplete.h" +#include "ParserAutoComplete.h" #include #include #include @@ -146,7 +147,16 @@ void ClientConnection::handle(const Messages::LanguageServer::AutoCompleteSugges return; } - auto suggestions = AutoComplete::get_suggestions(document->text(), { (size_t)message.cursor_line(), (size_t)max(message.cursor_column(), message.cursor_column() - 1) }); + Vector suggestions; + switch (m_auto_complete_mode) { + case AutoCompleteMode::Lexer: + suggestions = LexerAutoComplete::get_suggestions(document->text(), { (size_t)message.cursor_line(), (size_t)max(message.cursor_column(), message.cursor_column() - 1) }); + break; + case AutoCompleteMode::Parser: { + auto engine = ParserAutoComplete(document->text()); + suggestions = engine.get_suggestions({ (size_t)message.cursor_line(), (size_t)max(message.cursor_column(), message.cursor_column() - 1) }); + } + } post_message(Messages::LanguageClient::AutoCompleteSuggestions(move(suggestions))); } @@ -170,4 +180,15 @@ void ClientConnection::handle(const Messages::LanguageServer::SetFileContent& me document->set_text(content.view()); } +void ClientConnection::handle(const Messages::LanguageServer::SetAutoCompleteMode& message) +{ +#ifdef DEBUG_CPP_LANGUAGE_SERVER + dbgln("SetAutoCompleteMode: {}", message.mode()); +#endif + if (message.mode() == "Parser") + m_auto_complete_mode = AutoCompleteMode::Parser; + else + m_auto_complete_mode = AutoCompleteMode::Lexer; +} + } diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.h b/Userland/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.h index d0a7b4558c..3389ba8231 100644 --- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.h +++ b/Userland/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.h @@ -55,10 +55,18 @@ private: virtual void handle(const Messages::LanguageServer::FileEditRemoveText&) override; virtual void handle(const Messages::LanguageServer::SetFileContent&) override; virtual void handle(const Messages::LanguageServer::AutoCompleteSuggestions&) override; + virtual void handle(const Messages::LanguageServer::SetAutoCompleteMode&) override; RefPtr document_for(const String& file_name); HashMap> m_open_files; + + enum class AutoCompleteMode { + Lexer, + Parser + }; + + AutoCompleteMode m_auto_complete_mode { AutoCompleteMode::Lexer }; }; } diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/AutoComplete.cpp b/Userland/DevTools/HackStudio/LanguageServers/Cpp/LexerAutoComplete.cpp similarity index 85% rename from Userland/DevTools/HackStudio/LanguageServers/Cpp/AutoComplete.cpp rename to Userland/DevTools/HackStudio/LanguageServers/Cpp/LexerAutoComplete.cpp index b864563b4e..9a31679728 100644 --- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/AutoComplete.cpp +++ b/Userland/DevTools/HackStudio/LanguageServers/Cpp/LexerAutoComplete.cpp @@ -24,14 +24,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "AutoComplete.h" +#include "LexerAutoComplete.h" #include #include #include namespace LanguageServers::Cpp { -Vector AutoComplete::get_suggestions(const String& code, const GUI::TextPosition& autocomplete_position) +Vector LexerAutoComplete::get_suggestions(const String& code, const GUI::TextPosition& autocomplete_position) { auto lines = code.split('\n', true); Cpp::Lexer lexer(code); @@ -52,14 +52,14 @@ Vector AutoComplete::get_suggestions(const Str return suggestions; } -StringView AutoComplete::text_of_token(const Vector& lines, const Cpp::Token& token) +StringView LexerAutoComplete::text_of_token(const Vector& lines, const Cpp::Token& token) { ASSERT(token.m_start.line == token.m_end.line); ASSERT(token.m_start.column <= token.m_end.column); return lines[token.m_start.line].substring_view(token.m_start.column, token.m_end.column - token.m_start.column + 1); } -Optional AutoComplete::token_in_position(const Vector& tokens, const GUI::TextPosition& position) +Optional LexerAutoComplete::token_in_position(const Vector& tokens, const GUI::TextPosition& position) { for (size_t token_index = 0; token_index < tokens.size(); ++token_index) { auto& token = tokens[token_index]; @@ -74,7 +74,7 @@ Optional AutoComplete::token_in_position(const Vector& token return {}; } -Vector AutoComplete::identifier_prefixes(const Vector& lines, const Vector& tokens, size_t target_token_index) +Vector LexerAutoComplete::identifier_prefixes(const Vector& lines, const Vector& tokens, size_t target_token_index) { auto partial_input = text_of_token(lines, tokens[target_token_index]); Vector suggestions; diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/AutoComplete.h b/Userland/DevTools/HackStudio/LanguageServers/Cpp/LexerAutoComplete.h similarity index 97% rename from Userland/DevTools/HackStudio/LanguageServers/Cpp/AutoComplete.h rename to Userland/DevTools/HackStudio/LanguageServers/Cpp/LexerAutoComplete.h index b4096bd793..e482818cfc 100644 --- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/AutoComplete.h +++ b/Userland/DevTools/HackStudio/LanguageServers/Cpp/LexerAutoComplete.h @@ -36,9 +36,9 @@ namespace LanguageServers::Cpp { using namespace ::Cpp; -class AutoComplete { +class LexerAutoComplete { public: - AutoComplete() = delete; + LexerAutoComplete() = delete; static Vector get_suggestions(const String& code, const GUI::TextPosition& autocomplete_position); diff --git a/Userland/DevTools/HackStudio/LanguageServers/LanguageServer.ipc b/Userland/DevTools/HackStudio/LanguageServers/LanguageServer.ipc index de16fa14ec..405dbbab88 100644 --- a/Userland/DevTools/HackStudio/LanguageServers/LanguageServer.ipc +++ b/Userland/DevTools/HackStudio/LanguageServers/LanguageServer.ipc @@ -8,4 +8,5 @@ endpoint LanguageServer = 8001 SetFileContent(String file_name, String content) =| AutoCompleteSuggestions(String file_name, i32 cursor_line, i32 cursor_column) =| + SetAutoCompleteMode(String mode) =| } diff --git a/Userland/DevTools/HackStudio/LanguageServers/Shell/ClientConnection.h b/Userland/DevTools/HackStudio/LanguageServers/Shell/ClientConnection.h index bb7fc14bd9..cea922037e 100644 --- a/Userland/DevTools/HackStudio/LanguageServers/Shell/ClientConnection.h +++ b/Userland/DevTools/HackStudio/LanguageServers/Shell/ClientConnection.h @@ -56,6 +56,7 @@ private: virtual void handle(const Messages::LanguageServer::FileEditRemoveText&) override; virtual void handle(const Messages::LanguageServer::SetFileContent&) override; virtual void handle(const Messages::LanguageServer::AutoCompleteSuggestions&) override; + virtual void handle(const Messages::LanguageServer::SetAutoCompleteMode&) override { } RefPtr document_for(const String& file_name); diff --git a/Userland/Libraries/LibGUI/AutocompleteProvider.cpp b/Userland/Libraries/LibGUI/AutocompleteProvider.cpp index 383bead624..d136c17413 100644 --- a/Userland/Libraries/LibGUI/AutocompleteProvider.cpp +++ b/Userland/Libraries/LibGUI/AutocompleteProvider.cpp @@ -109,6 +109,7 @@ AutocompleteBox::AutocompleteBox(TextEditor& editor) m_suggestion_view = m_popup_window->set_main_widget(); m_suggestion_view->set_column_headers_visible(false); + m_suggestion_view->set_column_width(1, 100); } void AutocompleteBox::update_suggestions(Vector&& suggestions)