diff --git a/CHANGELOG.md b/CHANGELOG.md index acf8f8a7..a0db8c24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Changed -- Sync to upstream Luau 0.597 +- Sync to upstream Luau 0.599 - Prioritise `game:GetService()` as the first autocompletion entry when typing `game:` - Code blocks in hover and documentation now use `luau` as the syntax highlighting diff --git a/luau b/luau index 1d0b4491..24fdac4c 160000 --- a/luau +++ b/luau @@ -1 +1 @@ -Subproject commit 1d0b449181a41c00efc255a9a255616b843986b9 +Subproject commit 24fdac4c05f5ae189ede5153a83af4c1bd25351d diff --git a/src/operations/Completion.cpp b/src/operations/Completion.cpp index 8c776b84..3ac649d6 100644 --- a/src/operations/Completion.cpp +++ b/src/operations/Completion.cpp @@ -7,6 +7,9 @@ #include "LSP/LuauExt.hpp" #include "LSP/DocumentationParser.hpp" +LUAU_FASTFLAG(LuauClipExtraHasEndProps); +LUAU_FASTFLAG(LuauAutocompleteDoEnd); + /// Defining sort text levels assigned to completion items /// Note that sort text is lexicographically namespace SortText @@ -100,24 +103,66 @@ void WorkspaceFolder::endAutocompletion(const lsp::CompletionParams& params) return; auto unclosedBlock = false; - for (auto it = ancestry.rbegin(); it != ancestry.rend(); ++it) + if (FFlag::LuauClipExtraHasEndProps) { - if (auto* statForIn = (*it)->as(); statForIn && !statForIn->hasEnd) - unclosedBlock = true; - if (auto* statFor = (*it)->as(); statFor && !statFor->hasEnd) - unclosedBlock = true; - if (auto* statIf = (*it)->as(); statIf && !statIf->hasEnd) - unclosedBlock = true; - if (auto* statWhile = (*it)->as(); statWhile && !statWhile->hasEnd) - unclosedBlock = true; - if (auto* statBlock = (*it)->as(); statBlock && !statBlock->hasEnd) - unclosedBlock = true; - if (auto* exprFunction = (*it)->as(); exprFunction && !exprFunction->hasEnd) - unclosedBlock = true; + for (auto it = ancestry.rbegin(); it != ancestry.rend(); ++it) + { + if (auto* statForIn = (*it)->as(); statForIn && !statForIn->body->hasEnd) + unclosedBlock = true; + else if (auto* statFor = (*it)->as(); statFor && !statFor->body->hasEnd) + unclosedBlock = true; + else if (auto* statIf = (*it)->as()) + { + bool hasEnd = statIf->thenbody->hasEnd; + if (statIf->elsebody) + { + if (auto* elseBlock = statIf->elsebody->as()) + hasEnd = elseBlock->hasEnd; + } + + if (!hasEnd) + unclosedBlock = true; + } + else if (auto* statWhile = (*it)->as(); statWhile && !statWhile->body->hasEnd) + unclosedBlock = true; + else if (auto* exprFunction = (*it)->as(); exprFunction && !exprFunction->body->hasEnd) + unclosedBlock = true; + if (FFlag::LuauAutocompleteDoEnd) + { + if (auto* exprBlock = (*it)->as(); exprBlock && !exprBlock->hasEnd) + unclosedBlock = true; + + // FIX: if the unclosedBlock came from a repeat, then don't autocomplete, as it will be wrong! + if (auto* statRepeat = (*it)->as(); statRepeat && !statRepeat->body->hasEnd) + unclosedBlock = false; + } + } + } + else + { + for (auto it = ancestry.rbegin(); it != ancestry.rend(); ++it) + { + if (auto* statForIn = (*it)->as(); statForIn && !statForIn->DEPRECATED_hasEnd) + unclosedBlock = true; + if (auto* statFor = (*it)->as(); statFor && !statFor->DEPRECATED_hasEnd) + unclosedBlock = true; + if (auto* statIf = (*it)->as(); statIf && !statIf->DEPRECATED_hasEnd) + unclosedBlock = true; + if (auto* statWhile = (*it)->as(); statWhile && !statWhile->DEPRECATED_hasEnd) + unclosedBlock = true; + if (FFlag::LuauAutocompleteDoEnd) + { + if (auto* statBlock = (*it)->as(); statBlock && !statBlock->hasEnd) + unclosedBlock = true; + } + if (auto* exprFunction = (*it)->as(); exprFunction && !exprFunction->DEPRECATED_hasEnd) + unclosedBlock = true; + } } // TODO: we could potentially extend this further that just `hasEnd` // by inserting `then`, `until` `do` etc. It seems Studio does this + // NOTE: `until` can be inserted if `hasEnd` in a repeat block is false if (unclosedBlock) {