private static void AddSuggestionsForScopeFields(IntellisenseData.IntellisenseData intellisenseData, DType scope)
            {
                Contracts.AssertValue(intellisenseData);
                Contracts.Assert(scope.IsValid);

                foreach (var field in scope.GetNames(DPath.Root))
                {
                    IntellisenseHelper.AddSuggestion(intellisenseData, TexlLexer.PunctuatorAt + TexlLexer.EscapeName(field.Name.Value), SuggestionKind.Field, SuggestionIconKind.Other, field.Type, requiresSuggestionEscaping: false);
                }
            }
Beispiel #2
0
        public static void AddSuggestionsForEnums(IntellisenseData.IntellisenseData intellisenseData)
        {
            Contracts.AssertValue(intellisenseData);

            var suggestions          = intellisenseData.Suggestions;
            var substringSuggestions = intellisenseData.SubstringSuggestions;
            int countSuggBefore      = suggestions.Count;
            int countSubSuggBefore   = substringSuggestions.Count;

            foreach (var enumInfo in intellisenseData.EnumSymbols)
            {
                var enumType = enumInfo.EnumType;
                var enumName = enumInfo.Name;

                // TASK: 76039: Intellisense: Update intellisense to filter suggestions based on the expected type of the text being typed in UI
                IntellisenseHelper.AddSuggestion(intellisenseData, enumName, SuggestionKind.Enum, SuggestionIconKind.Other, enumType, requiresSuggestionEscaping: true);

                IntellisenseHelper.AddSuggestionsForEnum(intellisenseData, enumInfo, prefix: enumName + TexlLexer.PunctuatorDot);
            }

            if (suggestions.Count + substringSuggestions.Count == countSuggBefore + countSubSuggBefore + 1 && intellisenseData.SuggestUnqualifiedEnums)
            {
                string enumSuggestion = suggestions.Count > countSuggBefore ? suggestions[countSuggBefore].Text : substringSuggestions[countSubSuggBefore].Text;
                int    dotIndex       = enumSuggestion.LastIndexOf(TexlLexer.PunctuatorDot);

                // Assert '.' is not present or not at the beginning or the end of the EnumSuggestion
                Contracts.Assert(dotIndex == -1 || (0 < dotIndex && dotIndex < enumSuggestion.Length - 1));
                var unqualifiedEnum = enumSuggestion.Substring(dotIndex + 1);
                // If the Enum we are about suggest unqualified (i.e. just 'Blue' instead of Color!Blue)
                // has a name collision with some Item already in the suggestionlist we should not continue
                // and suggest it.
                if (suggestions.Any(x => x.Text == unqualifiedEnum) || substringSuggestions.Any(x => x.Text == unqualifiedEnum))
                {
                    return;
                }

                DType enumType;
                if (suggestions.Count > countSuggBefore)
                {
                    enumType = suggestions[countSuggBefore].Type;
                    suggestions.RemoveAt(suggestions.Count - 1);
                }
                else
                {
                    Contracts.Assert(substringSuggestions.Count > countSubSuggBefore);
                    enumType = substringSuggestions[countSubSuggBefore].Type;
                    substringSuggestions.RemoveAt(substringSuggestions.Count - 1);
                }

                // Add the unqualified Enum.
                // Note: The suggestion has already been escaped when it was previously added
                IntellisenseHelper.AddSuggestion(intellisenseData, unqualifiedEnum, SuggestionKind.Enum, SuggestionIconKind.Other, enumType, requiresSuggestionEscaping: false);
            }
        }
            internal void AddSuggestionsForNamespace(IntellisenseData.IntellisenseData intellisenseData, IEnumerable <TexlFunction> namespaceFunctions)
            {
                Contracts.AssertValue(intellisenseData);
                Contracts.AssertValue(namespaceFunctions);
                Contracts.AssertAllValues(namespaceFunctions);

                foreach (var function in namespaceFunctions)
                {
                    // Note we're using the unqualified name, since we're on the RHS of a "namespace." identifier.
                    IntellisenseHelper.AddSuggestion(intellisenseData, function.Name, SuggestionKind.Function, SuggestionIconKind.Function, function.ReturnType, requiresSuggestionEscaping: true);
                }
            }
Beispiel #4
0
        internal static void AddSuggestionsForGlobals(IntellisenseData.IntellisenseData intellisenseData)
        {
            Contracts.AssertValue(intellisenseData);

            intellisenseData.AddCustomSuggestionsForGlobals();

            // Suggest function namespaces
            var namespaces = intellisenseData.Binding.NameResolver.Functions.Select(func => func.Namespace).Distinct();

            foreach (var funcNamespace in namespaces)
            {
                if (funcNamespace == DPath.Root)
                {
                    continue;
                }

                IntellisenseHelper.AddSuggestion(intellisenseData, funcNamespace.Name, SuggestionKind.Global, SuggestionIconKind.Other, DType.Unknown, requiresSuggestionEscaping: true);
            }
        }
Beispiel #5
0
            /// <summary>
            /// Adds suggestions as appropriate to the internal Suggestions and SubstringSuggestions lists of intellisenseData.
            /// Returns true if intellisenseData is handled and no more suggestions are to be found and false otherwise.
            /// </summary>
            public bool Run(IntellisenseData.IntellisenseData intellisenseData)
            {
                Contracts.AssertValue(intellisenseData);

                if (!TryGetRecordNodeWithinACallNode(intellisenseData.CurNode, out RecordNode recordNode, out CallNode callNode))
                {
                    return(false);
                }

                // For the special case of an identifier of a record which is an argument of a function, we can
                // utilize the data provided to suggest relevant column names
                int cursorPos = intellisenseData.CursorPos;

                bool suggestionsAdded = false;

                Contracts.AssertValue(recordNode);
                Contracts.AssertValue(callNode);

                Identifier columnName = GetRecordIdentifierForCursorPosition(cursorPos, recordNode, intellisenseData.Script);

                if (columnName == null)
                {
                    return(false);
                }

                if (columnName.Token.Span.Min <= cursorPos)
                {
                    var tokenSpan         = columnName.Token.Span;
                    int replacementLength = tokenSpan.Min == cursorPos ? 0 : tokenSpan.Lim - tokenSpan.Min;
                    intellisenseData.SetMatchArea(tokenSpan.Min, cursorPos, replacementLength);
                }

                CallInfo info = intellisenseData.Binding.GetInfo(callNode);
                var      func = info.Function;

                if (func == null || !intellisenseData.IsFunctionElligibleForRecordSuggestions(func))
                {
                    return(false);
                }

                // Adding suggestions for callNode arguments which reference a collection's columns
                if (func.CanSuggestInputColumns)
                {
                    DType aggregateType = GetAggregateType(func, callNode, intellisenseData);
                    if (aggregateType.HasErrors || !aggregateType.IsAggregate)
                    {
                        return(false);
                    }

                    if (aggregateType.ContainsDataEntityType(DPath.Root))
                    {
                        bool error = false;
                        aggregateType = aggregateType.DropAllOfTableRelationships(ref error, DPath.Root);
                        if (error)
                        {
                            return(false);
                        }
                    }

                    foreach (TypedName tName in aggregateType.GetNames(DPath.Root))
                    {
                        var    usedName = tName.Name;
                        string maybeDisplayName;
                        if (DType.TryGetDisplayNameForColumn(aggregateType, usedName, out maybeDisplayName))
                        {
                            usedName = new DName(maybeDisplayName);
                        }

                        string suggestion = TexlLexer.EscapeName(usedName.Value) + (IntellisenseHelper.IsPunctuatorColonNextToCursor(cursorPos, intellisenseData.Script) ? "" : TexlLexer.PunctuatorColon);
                        suggestionsAdded |= IntellisenseHelper.AddSuggestion(intellisenseData, suggestion, SuggestionKind.Field, SuggestionIconKind.Other, DType.String, requiresSuggestionEscaping: false);
                    }

                    return(suggestionsAdded && columnName != null);
                }

                return(intellisenseData.TryAddFunctionRecordSuggestions(func, callNode, columnName));
            }