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); } }
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); } }
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); } }
/// <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)); }