private static CompletionListOptions GetOptions()

in src/LanguageServer/Impl/Completion/TopLevelCompletion.cs [97:157]


        private static CompletionListOptions GetOptions(Node statement, int index, out IndexSpan? span) {
            span = null;

            switch (statement) {
                // Disallow keywords, unless we're between the end of decorators and the
                // end of the "[async] def" keyword.
                case FunctionDefinition fd when index > fd.KeywordEndIndex || fd.Decorators != null && index < fd.Decorators.EndIndex:
                case ClassDefinition cd when index > cd.KeywordEndIndex || cd.Decorators != null && index < cd.Decorators.EndIndex:
                    return CompletionListOptions.NoKeywords;

                case TryStatementHandler tryStatement when tryStatement.Test is TupleExpression || index >= tryStatement.Test.StartIndex:
                    return CompletionListOptions.ExceptionsOnly;

                // Always allow keywords in non-keyword statements
                case ExpressionStatement _:
                case ImportStatement _:
                case FromImportStatement _:
                case null:
                    return CompletionListOptions.AllKeywords;

                // Allow keywords at start of assignment, but not in subsequent names
                case AssignmentStatement ss:
                    var firstAssign = ss.Left?.FirstOrDefault();
                    return firstAssign == null || index <= firstAssign.EndIndex
                        ? CompletionListOptions.AllKeywords : CompletionListOptions.ExpressionKeywords;

                // Allow keywords when we are in another keyword
                case Statement s when index <= s.KeywordEndIndex:
                    var keywordStart = s.KeywordEndIndex - s.KeywordLength;
                    if (index >= keywordStart) {
                        span = new IndexSpan(keywordStart, s.KeywordLength);
                    } else if ((s as IMaybeAsyncStatement)?.IsAsync == true) {
                        // Must be in the "async" at the start of the keyword
                        span = new IndexSpan(s.StartIndex, "async".Length);
                    }
                    return CompletionListOptions.AllKeywords;

                case RaiseStatement raise when raise.ExceptType != null && index >= raise.ExceptType.StartIndex || index > raise.KeywordEndIndex:
                    return CompletionListOptions.ExpressionKeywords | CompletionListOptions.ExceptionsOnly;

                // TryStatementHandler is 'except', but not a Statement subclass
                case TryStatementHandler except when index <= except.KeywordEndIndex:
                    var exceptKeywordStart = except.KeywordEndIndex - except.KeywordLength;
                    if (index >= exceptKeywordStart) {
                        span = new IndexSpan(exceptKeywordStart, except.KeywordLength);
                    }
                    return CompletionListOptions.AllKeywords;

                // Allow keywords in function body (we'd have a different statement if we were deeper)
                case FunctionDefinition fd when index >= fd.HeaderIndex:
                    return CompletionListOptions.AllKeywords;

                // Allow keywords within with blocks, but not in their definition
                case WithStatement ws:
                    return index >= ws.HeaderIndex || index <= ws.KeywordEndIndex
                        ? CompletionListOptions.AllKeywords : CompletionListOptions.ExpressionKeywords;

                default:
                    return CompletionListOptions.ExpressionKeywords;
            }
        }