summaryrefslogtreecommitdiff
path: root/DevTools/HackStudio
diff options
context:
space:
mode:
Diffstat (limited to 'DevTools/HackStudio')
-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) =|
}