1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 07:57:46 +00:00

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.
This commit is contained in:
Itamar 2021-01-23 16:55:19 +02:00 committed by Andreas Kling
parent 8ed96eb27c
commit fa18010477
14 changed files with 70 additions and 11 deletions

View file

@ -1,7 +1,8 @@
set(SOURCES
ClientConnection.cpp
main.cpp
AutoComplete.cpp
LexerAutoComplete.cpp
ParserAutoComplete.cpp
)
set(GENERATED_SOURCES

View file

@ -25,7 +25,8 @@
*/
#include "ClientConnection.h"
#include "AutoComplete.h"
#include "LexerAutoComplete.h"
#include "ParserAutoComplete.h"
#include <AK/Debug.h>
#include <AK/HashMap.h>
#include <LibCore/File.h>
@ -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<GUI::AutocompleteProvider::Entry> 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;
}
}

View file

@ -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<GUI::TextDocument> document_for(const String& file_name);
HashMap<String, NonnullRefPtr<GUI::TextDocument>> m_open_files;
enum class AutoCompleteMode {
Lexer,
Parser
};
AutoCompleteMode m_auto_complete_mode { AutoCompleteMode::Lexer };
};
}

View file

@ -24,14 +24,14 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "AutoComplete.h"
#include "LexerAutoComplete.h"
#include <AK/Debug.h>
#include <AK/HashTable.h>
#include <LibCpp/Lexer.h>
namespace LanguageServers::Cpp {
Vector<GUI::AutocompleteProvider::Entry> AutoComplete::get_suggestions(const String& code, const GUI::TextPosition& autocomplete_position)
Vector<GUI::AutocompleteProvider::Entry> 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<GUI::AutocompleteProvider::Entry> AutoComplete::get_suggestions(const Str
return suggestions;
}
StringView AutoComplete::text_of_token(const Vector<String>& lines, const Cpp::Token& token)
StringView LexerAutoComplete::text_of_token(const Vector<String>& 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<size_t> AutoComplete::token_in_position(const Vector<Cpp::Token>& tokens, const GUI::TextPosition& position)
Optional<size_t> LexerAutoComplete::token_in_position(const Vector<Cpp::Token>& 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<size_t> AutoComplete::token_in_position(const Vector<Cpp::Token>& token
return {};
}
Vector<GUI::AutocompleteProvider::Entry> AutoComplete::identifier_prefixes(const Vector<String>& lines, const Vector<Cpp::Token>& tokens, size_t target_token_index)
Vector<GUI::AutocompleteProvider::Entry> LexerAutoComplete::identifier_prefixes(const Vector<String>& lines, const Vector<Cpp::Token>& tokens, size_t target_token_index)
{
auto partial_input = text_of_token(lines, tokens[target_token_index]);
Vector<GUI::AutocompleteProvider::Entry> suggestions;

View file

@ -36,9 +36,9 @@ namespace LanguageServers::Cpp {
using namespace ::Cpp;
class AutoComplete {
class LexerAutoComplete {
public:
AutoComplete() = delete;
LexerAutoComplete() = delete;
static Vector<GUI::AutocompleteProvider::Entry> get_suggestions(const String& code, const GUI::TextPosition& autocomplete_position);

View file

@ -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) =|
}

View file

@ -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<GUI::TextDocument> document_for(const String& file_name);