summaryrefslogtreecommitdiff
path: root/DevTools
diff options
context:
space:
mode:
authorAnotherTest <ali.mpfard@gmail.com>2021-01-01 17:28:22 +0330
committerAndreas Kling <kling@serenityos.org>2021-01-02 11:37:01 +0100
commit7785d9715d9bc1b0c423a572eb40c6a86858ea1c (patch)
tree7845816bda04dc3a9cf7da402bc407eebec6616b /DevTools
parenta4a238ddc87d3e1a5e776a1d4b98891ee5871aee (diff)
downloadserenity-7785d9715d9bc1b0c423a572eb40c6a86858ea1c.zip
Playground: Enable automatic autocomplete in the editor
This makes it a bit more useful, as the user doesn't have to explicitly ask for completion, it just provides completions, and tries really hard to avoid suggesting things where they're not expected, for instance: (cursor positions denoted as pipes) ``` @G | {| foo: bar | foo | } ``` The user does not expect any suggestions in any of those cursor positions, so provide no suggestions for such cases. This prevents the automatic autocomplete getting in the way of the user, esp. when they try to press return fully expecting to go to a new line.
Diffstat (limited to 'DevTools')
-rw-r--r--DevTools/Playground/main.cpp30
1 files changed, 29 insertions, 1 deletions
diff --git a/DevTools/Playground/main.cpp b/DevTools/Playground/main.cpp
index 30ef723e26..00775aa9a6 100644
--- a/DevTools/Playground/main.cpp
+++ b/DevTools/Playground/main.cpp
@@ -64,11 +64,13 @@ private:
Vector<String> class_names;
Vector<State> previous_states;
bool should_push_state { true };
+ GUI::GMLToken* last_seen_token { nullptr };
for (auto& token : all_tokens) {
if (token.m_start.line > cursor.line() || (token.m_start.line == cursor.line() && token.m_start.column > cursor.column()))
break;
+ last_seen_token = &token;
switch (state) {
case Free:
if (token.m_type == GUI::GMLToken::Type::ClassName) {
@@ -102,9 +104,12 @@ private:
}
break;
case InIdentifier:
- state = AfterIdentifier;
+ if (token.m_type == GUI::GMLToken::Type::Colon)
+ state = AfterIdentifier;
break;
case AfterIdentifier:
+ if (token.m_type == GUI::GMLToken::Type::RightCurly || token.m_type == GUI::GMLToken::Type::LeftCurly)
+ break;
if (token.m_type == GUI::GMLToken::Type::ClassMarker) {
previous_states.append(AfterClassName);
state = Free;
@@ -119,6 +124,11 @@ private:
Vector<GUI::AutocompleteProvider::Entry> entries;
switch (state) {
case Free:
+ if (last_seen_token && last_seen_token->m_end.column + 1 != cursor.column() && last_seen_token->m_end.line == cursor.line()) {
+ // After some token, but with extra space, not on a new line.
+ // Nothing to put here.
+ break;
+ }
GUI::WidgetClassRegistration::for_each([&](const GUI::WidgetClassRegistration& registration) {
entries.empend(String::formatted("@{}", registration.class_name()), 0u);
});
@@ -126,6 +136,11 @@ private:
case InClassName:
if (class_names.is_empty())
break;
+ if (last_seen_token && last_seen_token->m_end.column + 1 != cursor.column() && last_seen_token->m_end.line == cursor.line()) {
+ // After a class name, but haven't seen braces.
+ // TODO: Suggest braces?
+ break;
+ }
GUI::WidgetClassRegistration::for_each([&](const GUI::WidgetClassRegistration& registration) {
if (registration.class_name().starts_with(class_names.last()))
entries.empend(registration.class_name(), class_names.last().length());
@@ -134,6 +149,11 @@ private:
case InIdentifier:
if (class_names.is_empty())
break;
+ if (last_seen_token && last_seen_token->m_end.column + 1 != cursor.column() && last_seen_token->m_end.line == cursor.line()) {
+ // After an identifier, but with extra space
+ // TODO: Maybe suggest a colon?
+ break;
+ }
if (auto registration = GUI::WidgetClassRegistration::find(class_names.last())) {
auto instance = registration->construct();
for (auto& it : instance->properties()) {
@@ -143,6 +163,13 @@ private:
}
break;
case AfterClassName:
+ if (last_seen_token && last_seen_token->m_end.line == cursor.line()) {
+ if (last_seen_token->m_type != GUI::GMLToken::Type::Identifier || last_seen_token->m_end.column + 1 != cursor.column()) {
+ // Inside braces, but on the same line as some other stuff (and not the continuation of one!)
+ // The user expects nothing here.
+ break;
+ }
+ }
if (!class_names.is_empty()) {
if (auto registration = GUI::WidgetClassRegistration::find(class_names.last())) {
auto instance = registration->construct();
@@ -191,6 +218,7 @@ int main(int argc, char** argv)
editor.set_syntax_highlighter(make<GUI::GMLSyntaxHighlighter>());
editor.set_autocomplete_provider(make<GMLAutocompleteProvider>());
+ editor.set_should_autocomplete_automatically(true);
editor.set_automatic_indentation_enabled(true);
editor.set_text(R"~~~(@GUI::Widget {
layout: @GUI::VerticalBoxLayout {