Skip to content

Commit

Permalink
Handle autocomplete in table when no initial character present (#1155)
Browse files Browse the repository at this point in the history
Closes #685
  • Loading branch information
JohnnyMorganz authored Jan 29, 2024
1 parent 9c588be commit c0b17da
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 0 deletions.
32 changes: 32 additions & 0 deletions Analysis/src/Autocomplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution);
LUAU_FASTFLAG(DebugLuauReadWriteProperties);
LUAU_FASTFLAGVARIABLE(LuauAutocompleteStringLiteralBounds, false);
LUAU_FASTFLAGVARIABLE(LuauAutocompleteTableKeysNoInitialCharacter, false);

static const std::unordered_set<std::string> kStatementStartingKeywords = {
"while", "if", "local", "repeat", "function", "do", "for", "return", "break", "continue", "type", "export"};
Expand Down Expand Up @@ -1742,6 +1743,37 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
}
}
}
else if (AstExprTable* exprTable = node->as<AstExprTable>(); exprTable && FFlag::LuauAutocompleteTableKeysNoInitialCharacter)
{
AutocompleteEntryMap result;

if (auto it = module->astExpectedTypes.find(exprTable))
{
result = autocompleteProps(*module, typeArena, builtinTypes, *it, PropIndexType::Key, ancestry);

// If the key type is a union of singleton strings,
// suggest those too.
if (auto ttv = get<TableType>(follow(*it)); ttv && ttv->indexer)
{
autocompleteStringSingleton(ttv->indexer->indexType, false, node, position, result);
}

// Remove keys that are already completed
for (const auto& item : exprTable->items)
{
if (!item.key)
continue;

if (auto stringKey = item.key->as<AstExprConstantString>())
result.erase(std::string(stringKey->value.data, stringKey->value.size));
}
}

// Also offer general expression suggestions
autocompleteExpression(sourceModule, *module, builtinTypes, typeArena, ancestry, position, result);

return {result, ancestry, AutocompleteContext::Property};
}
else if (isIdentifier(node) && (parent->is<AstStatExpr>() || parent->is<AstStatError>()))
return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry, AutocompleteContext::Statement};

Expand Down
38 changes: 38 additions & 0 deletions tests/Autocomplete.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
LUAU_FASTFLAG(LuauTraceTypesInNonstrictMode2)
LUAU_FASTFLAG(LuauSetMetatableDoesNotTimeTravel)
LUAU_FASTFLAG(LuauAutocompleteStringLiteralBounds);
LUAU_FASTFLAG(LuauAutocompleteTableKeysNoInitialCharacter)

using namespace Luau;

Expand Down Expand Up @@ -2693,6 +2694,43 @@ local t = {
CHECK_EQ(ac.context, AutocompleteContext::Property);
}

TEST_CASE_FIXTURE(ACFixture, "suggest_table_keys_no_initial_character")
{
ScopedFastFlag sff{FFlag::LuauAutocompleteTableKeysNoInitialCharacter, true};

check(R"(
type Test = { first: number, second: number }
local t: Test = { @1 }
)");

auto ac = autocomplete('1');
CHECK(ac.entryMap.count("first"));
CHECK(ac.entryMap.count("second"));
CHECK_EQ(ac.context, AutocompleteContext::Property);

check(R"(
type Test = { first: number, second: number }
local t: Test = { first = 1, @1 }
)");

ac = autocomplete('1');
CHECK_EQ(ac.entryMap.count("first"), 0);
CHECK(ac.entryMap.count("second"));
CHECK_EQ(ac.context, AutocompleteContext::Property);

check(R"(
type Properties = { TextScaled: boolean, Text: string }
local function create(props: Properties) end
create({ @1 })
)");

ac = autocomplete('1');
CHECK(ac.entryMap.count("TextScaled"));
CHECK(ac.entryMap.count("Text"));
CHECK_EQ(ac.context, AutocompleteContext::Property);
}

TEST_CASE_FIXTURE(ACFixture, "autocomplete_documentation_symbols")
{
loadDefinition(R"(
Expand Down

0 comments on commit c0b17da

Please sign in to comment.