summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnotherTest <ali.mpfard@gmail.com>2020-10-03 16:30:16 +0330
committerAndreas Kling <kling@serenityos.org>2020-10-04 23:12:28 +0200
commit9e73b0b696721706129a0d20a4603f681c905ab0 (patch)
tree2d08306171b86efbdefd59d4d129ac8cfb1b0a6c
parentb42c6ea281add0d5ad3bd2bec52742353c718603 (diff)
downloadserenity-9e73b0b696721706129a0d20a4603f681c905ab0.zip
HackStudio: Relay completions requests to the language server unfiltered
Previously, the client would decide when to ask the server for completions, and it would only do so for identifiers that had spans (determined via the highlighter!). Swap this around and make the server decide if it wants to complete something. This commit also adds a CompletionKind (which only has one value: Identifier), to work with other kinds of completions as well.
-rw-r--r--DevTools/HackStudio/AutoCompleteBox.cpp33
-rw-r--r--DevTools/HackStudio/AutoCompleteBox.h5
-rw-r--r--DevTools/HackStudio/AutoCompleteResponse.h76
-rw-r--r--DevTools/HackStudio/Editor.cpp24
-rw-r--r--DevTools/HackStudio/Editor.h1
-rw-r--r--DevTools/HackStudio/LanguageClient.cpp2
-rw-r--r--DevTools/HackStudio/LanguageClient.h8
-rw-r--r--DevTools/HackStudio/LanguageServers/Cpp/AutoComplete.cpp10
-rw-r--r--DevTools/HackStudio/LanguageServers/Cpp/AutoComplete.h6
-rw-r--r--DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.cpp2
-rw-r--r--DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.h6
-rw-r--r--DevTools/HackStudio/LanguageServers/LanguageClient.ipc2
12 files changed, 125 insertions, 50 deletions
diff --git a/DevTools/HackStudio/AutoCompleteBox.cpp b/DevTools/HackStudio/AutoCompleteBox.cpp
index 444a83038e..d5950c125c 100644
--- a/DevTools/HackStudio/AutoCompleteBox.cpp
+++ b/DevTools/HackStudio/AutoCompleteBox.cpp
@@ -37,7 +37,7 @@ static RefPtr<Gfx::Bitmap> s_cplusplus_icon;
class AutoCompleteSuggestionModel final : public GUI::Model {
public:
- explicit AutoCompleteSuggestionModel(Vector<String>&& suggestions)
+ explicit AutoCompleteSuggestionModel(Vector<AutoCompleteResponse>&& suggestions)
: m_suggestions(move(suggestions))
{
}
@@ -48,6 +48,12 @@ public:
__Column_Count,
};
+ enum InternalRole {
+ __ModelRoleCustom = (int)GUI::ModelRole::Custom,
+ PartialInputLength,
+ Kind,
+ };
+
virtual int row_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override { return m_suggestions.size(); }
virtual int column_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override { return Column::__Column_Count; }
virtual GUI::Variant data(const GUI::ModelIndex& index, GUI::ModelRole role) const override
@@ -55,21 +61,29 @@ public:
auto& suggestion = m_suggestions.at(index.row());
if (role == GUI::ModelRole::Display) {
if (index.column() == Column::Name) {
- return suggestion;
+ return suggestion.completion;
}
if (index.column() == Column::Icon) {
// TODO: Have separate icons for fields, functions, methods etc
- if (suggestion.ends_with(".cpp"))
+ // FIXME: Probably should have different icons for the different kinds, rather than for "c++".
+ if (suggestion.kind == CompletionKind::Identifier)
return *s_cplusplus_icon;
return *s_cplusplus_icon;
}
}
+
+ if ((int)role == InternalRole::Kind)
+ return (u32)suggestion.kind;
+
+ if ((int)role == InternalRole::PartialInputLength)
+ return (i64)suggestion.partial_input_length;
+
return {};
}
virtual void update() override {};
private:
- Vector<String> m_suggestions;
+ Vector<AutoCompleteResponse> m_suggestions;
};
AutoCompleteBox::~AutoCompleteBox() { }
@@ -89,9 +103,8 @@ AutoCompleteBox::AutoCompleteBox(WeakPtr<Editor> editor)
m_suggestion_view->set_column_headers_visible(false);
}
-void AutoCompleteBox::update_suggestions(String partial_input, Vector<String>&& suggestions)
+void AutoCompleteBox::update_suggestions(Vector<AutoCompleteResponse>&& suggestions)
{
- m_partial_input = partial_input;
if (suggestions.is_empty())
return;
@@ -112,7 +125,6 @@ void AutoCompleteBox::show(Gfx::IntPoint suggstion_box_location)
void AutoCompleteBox::close()
{
- m_partial_input.empty();
m_popup_window->hide();
}
@@ -155,11 +167,10 @@ void AutoCompleteBox::apply_suggestion()
auto suggestion_index = m_suggestion_view->model()->index(selected_index.row(), AutoCompleteSuggestionModel::Column::Name);
auto suggestion = suggestion_index.data().to_string();
+ size_t partial_length = suggestion_index.data((GUI::ModelRole)AutoCompleteSuggestionModel::InternalRole::PartialInputLength).to_i64();
- ASSERT(!m_partial_input.is_null());
- ASSERT(suggestion.starts_with(m_partial_input));
-
- auto completion = suggestion.substring(m_partial_input.length(), suggestion.length() - m_partial_input.length());
+ ASSERT(suggestion.length() >= partial_length);
+ auto completion = suggestion.substring_view(partial_length, suggestion.length() - partial_length);
m_editor->insert_at_cursor_or_replace_selection(completion);
}
diff --git a/DevTools/HackStudio/AutoCompleteBox.h b/DevTools/HackStudio/AutoCompleteBox.h
index 0fe715aa12..ef4bdcf4a5 100644
--- a/DevTools/HackStudio/AutoCompleteBox.h
+++ b/DevTools/HackStudio/AutoCompleteBox.h
@@ -26,18 +26,20 @@
#pragma once
+#include "AutoCompleteResponse.h"
#include <AK/WeakPtr.h>
#include <LibGUI/Widget.h>
namespace HackStudio {
class Editor;
+
class AutoCompleteBox final {
public:
explicit AutoCompleteBox(WeakPtr<Editor>);
~AutoCompleteBox();
- void update_suggestions(const String partial_input, Vector<String>&& suggestions);
+ void update_suggestions(Vector<AutoCompleteResponse>&& suggestions);
void show(Gfx::IntPoint suggstion_box_location);
void close();
@@ -51,6 +53,5 @@ private:
WeakPtr<Editor> m_editor;
RefPtr<GUI::Window> m_popup_window;
RefPtr<GUI::TableView> m_suggestion_view;
- String m_partial_input;
};
}
diff --git a/DevTools/HackStudio/AutoCompleteResponse.h b/DevTools/HackStudio/AutoCompleteResponse.h
new file mode 100644
index 0000000000..e1fd298dec
--- /dev/null
+++ b/DevTools/HackStudio/AutoCompleteResponse.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020, the SerenityOS developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <AK/String.h>
+#include <AK/Types.h>
+#include <LibIPC/Decoder.h>
+#include <LibIPC/Encoder.h>
+
+namespace HackStudio {
+
+enum class CompletionKind {
+ Identifier,
+};
+
+struct AutoCompleteResponse {
+ String completion;
+ size_t partial_input_length { 0 };
+ CompletionKind kind { CompletionKind::Identifier };
+};
+
+}
+
+namespace IPC {
+
+template<>
+inline bool encode(IPC::Encoder& encoder, const HackStudio::AutoCompleteResponse& response)
+{
+ encoder << response.completion;
+ encoder << (u64)response.partial_input_length;
+ encoder << (u32)response.kind;
+ return true;
+}
+
+template<>
+inline bool decode(IPC::Decoder& decoder, HackStudio::AutoCompleteResponse& response)
+{
+ u32 kind = 0;
+ u64 partial_input_length = 0;
+ bool ok = decoder.decode(response.completion)
+ && decoder.decode(partial_input_length)
+ && decoder.decode(kind);
+
+ if (ok) {
+ response.kind = static_cast<HackStudio::CompletionKind>(kind);
+ response.partial_input_length = partial_input_length;
+ }
+
+ return ok;
+}
+
+}
diff --git a/DevTools/HackStudio/Editor.cpp b/DevTools/HackStudio/Editor.cpp
index c52a8d1a3b..45398c1b35 100644
--- a/DevTools/HackStudio/Editor.cpp
+++ b/DevTools/HackStudio/Editor.cpp
@@ -494,28 +494,10 @@ void Editor::set_document(GUI::TextDocument& doc)
Optional<Editor::AutoCompleteRequestData> Editor::get_autocomplete_request_data()
{
- auto highlighter = wrapper().editor().syntax_highlighter();
- if (!highlighter)
+ if (!wrapper().editor().m_language_client)
return {};
- auto& spans = document().spans();
- for (size_t span_index = 2; span_index < spans.size(); ++span_index) {
- auto& span = spans[span_index];
- if (!span.range.contains(cursor())) {
- continue;
- }
-
- if (highlighter->is_identifier(spans[span_index - 1].data)) {
- auto completion_span = spans[span_index - 1];
- auto adjusted_range = completion_span.range;
- auto end_line_length = document().line(completion_span.range.end().line()).length();
- adjusted_range.end().set_column(min(end_line_length, adjusted_range.end().column() + 1));
- auto text_in_span = document().text_in_range(adjusted_range);
-
- return AutoCompleteRequestData { completion_span.range.end(), text_in_span };
- }
- }
- return {};
+ return Editor::AutoCompleteRequestData { { cursor().line(), cursor().column() > 0 ? cursor().column() - 1 : 0 } };
}
void Editor::update_autocomplete(const AutoCompleteRequestData& data)
@@ -531,7 +513,7 @@ void Editor::update_autocomplete(const AutoCompleteRequestData& data)
show_autocomplete(data);
- m_autocomplete_box->update_suggestions(data.partial_input, move(suggestions));
+ m_autocomplete_box->update_suggestions(move(suggestions));
m_autocomplete_in_focus = true;
};
diff --git a/DevTools/HackStudio/Editor.h b/DevTools/HackStudio/Editor.h
index fb208a2fa0..90273ff27f 100644
--- a/DevTools/HackStudio/Editor.h
+++ b/DevTools/HackStudio/Editor.h
@@ -86,7 +86,6 @@ private:
struct AutoCompleteRequestData {
GUI::TextPosition position;
- String partial_input;
};
Optional<AutoCompleteRequestData> get_autocomplete_request_data();
diff --git a/DevTools/HackStudio/LanguageClient.cpp b/DevTools/HackStudio/LanguageClient.cpp
index 36539802d3..f394dc674d 100644
--- a/DevTools/HackStudio/LanguageClient.cpp
+++ b/DevTools/HackStudio/LanguageClient.cpp
@@ -61,7 +61,7 @@ void LanguageClient::request_autocomplete(const String& path, size_t cursor_line
m_connection.post_message(Messages::LanguageServer::AutoCompleteSuggestions(path, cursor_line, cursor_column));
}
-void LanguageClient::provide_autocomplete_suggestions(const Vector<String>& suggestions)
+void LanguageClient::provide_autocomplete_suggestions(const Vector<AutoCompleteResponse>& suggestions)
{
if (on_autocomplete_suggestions)
on_autocomplete_suggestions(suggestions);
diff --git a/DevTools/HackStudio/LanguageClient.h b/DevTools/HackStudio/LanguageClient.h
index 905c09c951..7d0f56d228 100644
--- a/DevTools/HackStudio/LanguageClient.h
+++ b/DevTools/HackStudio/LanguageClient.h
@@ -26,12 +26,14 @@
#pragma once
+#include "AutoCompleteResponse.h"
#include <AK/Forward.h>
#include <AK/LexicalPath.h>
#include <AK/Types.h>
+#include <LibIPC/ServerConnection.h>
+
#include <DevTools/HackStudio/LanguageServers/LanguageClientEndpoint.h>
#include <DevTools/HackStudio/LanguageServers/LanguageServerEndpoint.h>
-#include <LibIPC/ServerConnection.h>
namespace HackStudio {
@@ -104,9 +106,9 @@ public:
virtual void remove_text(const String& path, size_t from_line, size_t from_column, size_t to_line, size_t to_column);
virtual void request_autocomplete(const String& path, size_t cursor_line, size_t cursor_column);
- void provide_autocomplete_suggestions(const Vector<String>&);
+ void provide_autocomplete_suggestions(const Vector<AutoCompleteResponse>&);
- Function<void(Vector<String>)> on_autocomplete_suggestions;
+ Function<void(Vector<AutoCompleteResponse>)> on_autocomplete_suggestions;
private:
ServerConnection& m_connection;
diff --git a/DevTools/HackStudio/LanguageServers/Cpp/AutoComplete.cpp b/DevTools/HackStudio/LanguageServers/Cpp/AutoComplete.cpp
index 1ebdd9a8d6..6fda4cff65 100644
--- a/DevTools/HackStudio/LanguageServers/Cpp/AutoComplete.cpp
+++ b/DevTools/HackStudio/LanguageServers/Cpp/AutoComplete.cpp
@@ -32,7 +32,7 @@
namespace LanguageServers::Cpp {
-Vector<String> AutoComplete::get_suggestions(const String& code, GUI::TextPosition autocomplete_position)
+Vector<AutoCompleteResponse> AutoComplete::get_suggestions(const String& code, GUI::TextPosition autocomplete_position)
{
auto lines = code.split('\n', true);
Lexer lexer(code);
@@ -46,7 +46,7 @@ Vector<String> AutoComplete::get_suggestions(const String& code, GUI::TextPositi
#ifdef DEBUG_AUTOCOMPLETE
for (auto& suggestion : suggestions) {
- dbg() << "suggestion: " << suggestion;
+ dbg() << "suggestion: " << suggestion.completion;
}
#endif
@@ -71,10 +71,10 @@ Optional<size_t> AutoComplete::token_in_position(const Vector<Cpp::Token>& token
return {};
}
-Vector<String> AutoComplete::identifier_prefixes(const Vector<String> lines, const Vector<Cpp::Token>& tokens, size_t target_token_index)
+Vector<AutoCompleteResponse> AutoComplete::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<String> suggestions;
+ Vector<AutoCompleteResponse> suggestions;
HashTable<String> suggestions_lookup; // To avoid duplicate results
@@ -85,7 +85,7 @@ Vector<String> AutoComplete::identifier_prefixes(const Vector<String> lines, con
auto text = text_of_token(lines, token);
if (text.starts_with(partial_input) && !suggestions_lookup.contains(text)) {
suggestions_lookup.set(text);
- suggestions.append(text);
+ suggestions.append({ text, partial_input.length(), HackStudio::CompletionKind::Identifier });
}
}
return suggestions;
diff --git a/DevTools/HackStudio/LanguageServers/Cpp/AutoComplete.h b/DevTools/HackStudio/LanguageServers/Cpp/AutoComplete.h
index ad0104f5e1..d0b772b0ad 100644
--- a/DevTools/HackStudio/LanguageServers/Cpp/AutoComplete.h
+++ b/DevTools/HackStudio/LanguageServers/Cpp/AutoComplete.h
@@ -28,23 +28,25 @@
#include <AK/String.h>
#include <AK/Vector.h>
+#include <DevTools/HackStudio/AutoCompleteResponse.h>
#include <LibCpp/Lexer.h>
#include <LibGUI/TextPosition.h>
namespace LanguageServers::Cpp {
using namespace ::Cpp;
+using ::HackStudio::AutoCompleteResponse;
class AutoComplete {
public:
AutoComplete() = delete;
- static Vector<String> get_suggestions(const String& code, GUI::TextPosition autocomplete_position);
+ static Vector<AutoCompleteResponse> get_suggestions(const String& code, GUI::TextPosition autocomplete_position);
private:
static Optional<size_t> token_in_position(const Vector<Cpp::Token>&, GUI::TextPosition);
static String text_of_token(const Vector<String> lines, const Cpp::Token&);
- static Vector<String> identifier_prefixes(const Vector<String> lines, const Vector<Cpp::Token>&, size_t target_token_index);
+ static Vector<AutoCompleteResponse> identifier_prefixes(const Vector<String> lines, const Vector<Cpp::Token>&, size_t target_token_index);
};
}
diff --git a/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.cpp b/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.cpp
index 5ffc750b8b..f57719f8cd 100644
--- a/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.cpp
+++ b/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.cpp
@@ -159,7 +159,7 @@ void ClientConnection::handle(const Messages::LanguageServer::AutoCompleteSugges
return;
}
- Vector<String> suggestions = AutoComplete::get_suggestions(document->text(), { (size_t)message.cursor_line(), (size_t)message.cursor_column() });
+ auto suggestions = AutoComplete::get_suggestions(document->text(), { (size_t)message.cursor_line(), (size_t)message.cursor_column() });
post_message(Messages::LanguageClient::AutoCompleteSuggestions(move(suggestions)));
}
diff --git a/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.h b/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.h
index 006688a524..2df3519d92 100644
--- a/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.h
+++ b/DevTools/HackStudio/LanguageServers/Cpp/ClientConnection.h
@@ -28,11 +28,13 @@
#include <AK/HashMap.h>
#include <AK/LexicalPath.h>
-#include <DevTools/HackStudio/LanguageServers/LanguageClientEndpoint.h>
-#include <DevTools/HackStudio/LanguageServers/LanguageServerEndpoint.h>
+#include <DevTools/HackStudio/AutoCompleteResponse.h>
#include <LibGUI/TextDocument.h>
#include <LibIPC/ClientConnection.h>
+#include <DevTools/HackStudio/LanguageServers/LanguageClientEndpoint.h>
+#include <DevTools/HackStudio/LanguageServers/LanguageServerEndpoint.h>
+
namespace LanguageServers::Cpp {
class ClientConnection final
diff --git a/DevTools/HackStudio/LanguageServers/LanguageClient.ipc b/DevTools/HackStudio/LanguageServers/LanguageClient.ipc
index dbd0d33d46..66a63d53fb 100644
--- a/DevTools/HackStudio/LanguageServers/LanguageClient.ipc
+++ b/DevTools/HackStudio/LanguageServers/LanguageClient.ipc
@@ -1,4 +1,4 @@
endpoint LanguageClient = 8002
{
- AutoCompleteSuggestions(Vector<String> suggestions) =|
+ AutoCompleteSuggestions(Vector<HackStudio::AutoCompleteResponse> suggestions) =|
}