/// <summary> /// Adds suggestions for an enum, with an optional prefix. /// </summary> /// <param name="intellisenseData"></param> /// <param name="enumInfo"></param> /// <param name="prefix"></param> internal static void AddSuggestionsForEnum(IntellisenseData.IntellisenseData intellisenseData, EnumSymbol enumInfo, string prefix = "") { Contracts.AssertValue(intellisenseData); Contracts.AssertValue(enumInfo); Contracts.AssertValue(prefix); bool anyCollisionExists = false; var locNameTypePairs = new List <Tuple <String, DType> >(); // We do not need to get the localized names since GetNames will only return invariant. // Instead, we use the invariant names later with the enumInfo to retrieve the localized name. foreach (var typedName in enumInfo.EnumType.GetNames(DPath.Root)) { string locName; enumInfo.TryGetLocValueName(typedName.Name.Value, out locName).Verify(); string escapedLocName = TexlLexer.EscapeName(locName); var collisionExists = intellisenseData.DoesNameCollide(locName); if (collisionExists) { string candidate = prefix + escapedLocName; bool canAddSuggestion = _addSuggestionDryRunHelper.AddSuggestion(intellisenseData, candidate, SuggestionKind.Global, SuggestionIconKind.Other, typedName.Type, false); anyCollisionExists = anyCollisionExists || canAddSuggestion; } locNameTypePairs.Add(new Tuple <String, DType>(escapedLocName, typedName.Type)); } foreach (var locNameTypePair in locNameTypePairs) { string suggestion = anyCollisionExists || !intellisenseData.SuggestUnqualifiedEnums ? prefix + locNameTypePair.Item1 : locNameTypePair.Item1; AddSuggestion(intellisenseData, suggestion, SuggestionKind.Global, SuggestionIconKind.Other, locNameTypePair.Item2, false); } }
// Convert this DPath to a string in dotted syntax, such as "screen1.group6.label3" public string ToDottedSyntax(string punctuator = ".", bool escapeInnerName = false) { Contracts.AssertNonEmpty(punctuator); Contracts.Assert(punctuator.Length == 1); Contracts.Assert(".!".IndexOf(punctuator[0]) >= 0); if (IsRoot) { return(string.Empty); } Contracts.Assert(Length > 0); int count = 0; for (Node node = _node; node != null; node = node.Parent) { count += node.Name.Value.Length; } StringBuilder sb = new StringBuilder(count + Length - 1); string sep = string.Empty; for (int i = 0; i < Length; i++) { sb.Append(sep); var escapedName = escapeInnerName ? TexlLexer.EscapeName(this[i]) : this[i]; sb.Append(escapedName); sep = punctuator; } return(sb.ToString()); }
private static IEnumerable <KeyValuePair <string, DType> > TimeUnitSuggestions(TryGetEnumSymbol tryGetEnumSymbol, bool suggestUnqualifedEnums, DType scopeType, int argumentIndex, out bool requiresSuggestionEscaping) { Contracts.Assert(scopeType.IsValid); Contracts.Assert(2 == argumentIndex); requiresSuggestionEscaping = false; var retVal = new List <KeyValuePair <string, DType> >(); if (argumentIndex == 2 && tryGetEnumSymbol(EnumConstants.TimeUnitEnumString, out var enumInfo)) { Contracts.AssertValue(enumInfo); foreach (var name in enumInfo.EnumType.GetNames(DPath.Root)) { string locName; enumInfo.TryGetLocValueName(name.Name.Value, out locName).Verify(); if (suggestUnqualifedEnums) { retVal.Add(new KeyValuePair <string, DType>(TexlLexer.EscapeName(locName), name.Type)); } else { retVal.Add(new KeyValuePair <string, DType>(TexlLexer.EscapeName(enumInfo.Name) + TexlLexer.PunctuatorDot + TexlLexer.EscapeName(locName), name.Type)); } } } return(retVal); }
// This method returns the suggestions for latter arguments of the If function based on the second argument (the true result) private static IEnumerable <KeyValuePair <string, DType> > IfSuggestions(TryGetEnumSymbol tryGetEnumSymbol, bool suggestUnqualifedEnums, DType scopeType, int argumentIndex, out bool requiresSuggestionEscaping) { Contracts.Assert(scopeType.IsValid); Contracts.Assert(0 <= argumentIndex); requiresSuggestionEscaping = false; if (argumentIndex <= 1) { return(EnumerableUtils.Yield <KeyValuePair <string, DType> >()); } return(scopeType .GetNames(DPath.Root) .Select(name => new KeyValuePair <string, DType>(TexlLexer.EscapeName(name.Name.Value), name.Type))); }
/// <summary> /// Adds suggestions that start with the MatchingString from the given type. /// </summary> internal static void AddTopLevelSuggestions(IntellisenseData.IntellisenseData intellisenseData, DType type, string prefix = "") { Contracts.AssertValue(intellisenseData); Contracts.Assert(type.IsValid); Contracts.Assert(prefix.Length == 0 || (TexlLexer.PunctuatorBang + TexlLexer.PunctuatorDot).IndexOf(prefix[prefix.Length - 1]) >= 0); foreach (TypedName tName in type.GetAllNames(DPath.Root)) { if (!intellisenseData.TryAddCustomColumnTypeSuggestions(tName.Type)) { var usedName = tName.Name; string maybeDisplayName; if (DType.TryGetDisplayNameForColumn(type, usedName, out maybeDisplayName)) { usedName = new DName(maybeDisplayName); } AddSuggestion(intellisenseData, prefix + TexlLexer.EscapeName(usedName.Value), SuggestionKind.Global, SuggestionIconKind.Other, tName.Type, requiresSuggestionEscaping: false); } } }
/// <summary> /// This method returns the suggestions for second and third arguments of the Text function. /// </summary> /// <param name="tryGetEnumSymbol"> /// Getter for enum symbols intended for the suggestions /// </param> /// <param name="suggestUnescapedEnums"> /// Whether to suggest unescaped enums /// </param> /// <param name="scopeType"> /// Type of the enclosing scope from where intellisense is run /// </param> /// <param name="argumentIndex"> /// The current index of the argument from where intellisense is run /// </param> /// <param name="requiresSuggestionEscaping"> /// Set to whether the argument needs to be string escaped /// </param> /// <returns> /// Enumerable of suggestions wherein the key is the suggestion text and the value is its type /// </returns> private static IEnumerable <KeyValuePair <string, DType> > TextSuggestions(TryGetEnumSymbol tryGetEnumSymbol, bool suggestUnescapedEnums, DType scopeType, int argumentIndex, out bool requiresSuggestionEscaping) { Contracts.Assert(scopeType.IsValid); Contracts.Assert(0 <= argumentIndex); requiresSuggestionEscaping = true; if (argumentIndex != 1 && argumentIndex != 2) { return(EnumerableUtils.Yield <KeyValuePair <string, DType> >()); } if (argumentIndex == 1) { if (!DType.DateTime.Accepts(scopeType) || !tryGetEnumSymbol(EnumConstants.DateTimeFormatEnumString, out var enumInfo)) { return(EnumerableUtils.Yield <KeyValuePair <string, DType> >()); } var retVal = new List <KeyValuePair <string, DType> >(); Contracts.AssertValue(enumInfo); requiresSuggestionEscaping = false; foreach (var name in enumInfo.EnumType.GetNames(DPath.Root)) { string locName; enumInfo.TryGetLocValueName(name.Name.Value, out locName).Verify(); retVal.Add(new KeyValuePair <string, DType>(TexlLexer.EscapeName(enumInfo.Name) + TexlLexer.PunctuatorDot + TexlLexer.EscapeName(locName), name.Type)); } return(retVal); } else { Contracts.Assert(argumentIndex == 2); requiresSuggestionEscaping = false; return(GetLanguageCodeSuggestions()); } }
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 bool AddSuggestion(IntellisenseData.IntellisenseData intellisenseData, string suggestion, SuggestionKind suggestionKind, SuggestionIconKind iconKind, DType type, bool requiresSuggestionEscaping, uint sortPriority = 0) { Contracts.AssertValue(intellisenseData); Contracts.AssertValue(suggestion); if (!intellisenseData.DetermineSuggestibility(suggestion, type)) { return(false); } IntellisenseSuggestionList suggestions = intellisenseData.Suggestions; IntellisenseSuggestionList substringSuggestions = intellisenseData.SubstringSuggestions; int matchingLength = intellisenseData.MatchingLength; string matchingStr = intellisenseData.MatchingStr; string boundTo = intellisenseData.BoundTo; var valueToSuggest = requiresSuggestionEscaping ? TexlLexer.EscapeName(suggestion) : suggestion; int highlightStart = suggestion.IndexOf(matchingStr, StringComparison.OrdinalIgnoreCase); // If the suggestion has special characters we need to find the highlightStart index by escaping the matching string as well. // Because, the suggestion could be something like 'Ident with Space' and the user might have typed Ident. In this case, // we want to highlight only Ident while displaying 'Ident with Space'. if (requiresSuggestionEscaping && !string.IsNullOrEmpty(matchingStr) && valueToSuggest != suggestion && highlightStart == 0) { highlightStart++; } else { matchingLength--; } int highlightEnd = highlightStart + matchingStr.Length; if (IntellisenseHelper.IsMatch(suggestion, matchingStr)) { // In special circumstance where the user escapes an identifier where they don't have to, the matching length will // include the starting delimiter that user provided, where as the suggestion would not include any delimiters. // Hence we have to count for that fact. if (matchingLength > 0 & matchingLength > matchingStr.Length) { highlightEnd = matchingLength > valueToSuggest.Length ? valueToSuggest.Length : matchingLength; } UIString UIsuggestion = ConstructUIString(suggestionKind, type, suggestions, valueToSuggest, highlightStart, highlightEnd); IntellisenseSuggestion candidate = new IntellisenseSuggestion(UIsuggestion, suggestionKind, iconKind, type, boundTo, -1, string.Empty, null, sortPriority); return(CheckAndAddSuggestion(suggestions, candidate)); } if (highlightStart > -1) { UIString UIsuggestion = ConstructUIString(suggestionKind, type, substringSuggestions, valueToSuggest, highlightStart, highlightEnd); IntellisenseSuggestion candidate = new IntellisenseSuggestion(UIsuggestion, suggestionKind, iconKind, type, boundTo, -1, string.Empty, null, sortPriority); return(CheckAndAddSuggestion(substringSuggestions, candidate)); } return(false); }
/// <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)); }