internal static IEnumerable <KeyValuePair <string, DType> > GetSuggestionsFromType(DType typeToSuggestFrom, DType suggestionType) { Contracts.AssertValid(typeToSuggestFrom); Contracts.AssertValid(suggestionType); // If no suggestion type provided, accept all suggestions. if (suggestionType == DType.Invalid) { suggestionType = DType.Error; } List <KeyValuePair <string, DType> > suggestions = new List <KeyValuePair <string, DType> >(); foreach (TypedName tName in typeToSuggestFrom.GetNames(DPath.Root)) { if (suggestionType.Accepts(tName.Type)) { var usedName = tName.Name.Value; string maybeDisplayName; if (DType.TryGetDisplayNameForColumn(typeToSuggestFrom, usedName, out maybeDisplayName)) { usedName = maybeDisplayName; } suggestions.Add(new KeyValuePair <string, DType>(usedName, tName.Type)); } } return(suggestions); }
/// <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); } } }
internal static void AddSuggestionsForNamesInType(DType type, IntellisenseData.IntellisenseData data, bool createTableSuggestion) { Contracts.AssertValid(type); Contracts.AssertValue(data); foreach (var field in type.GetNames(DPath.Root)) { var usedName = field.Name; string maybeDisplayName; if (DType.TryGetDisplayNameForColumn(type, usedName, out maybeDisplayName)) { usedName = new DName(maybeDisplayName); } DType suggestionType = field.Type; if (createTableSuggestion) { suggestionType = DType.CreateTable(new TypedName(type, usedName)); } AddSuggestion(data, usedName.Value, SuggestionKind.Field, SuggestionIconKind.Other, suggestionType, requiresSuggestionEscaping: true); } }
public override bool CheckInvocation(TexlBinding binding, TexlNode[] args, DType[] argTypes, IErrorContainer errors, out DType returnType, out Dictionary <TexlNode, DType> nodeToCoercedTypeMap) { Contracts.AssertValue(args); Contracts.AssertValue(argTypes); Contracts.Assert(args.Length == argTypes.Length); Contracts.AssertValue(errors); Contracts.Assert(MinArity <= args.Length && args.Length <= MaxArity); bool fArgsValid = base.CheckInvocation(args, argTypes, errors, out returnType, out nodeToCoercedTypeMap); // The first arg determines the scope type for the lambda params, and the return type. DType typeScope; fArgsValid &= ScopeInfo.CheckInput(args[0], argTypes[0], errors, out typeScope); Contracts.Assert(typeScope.IsRecord); // The result type has N additional columns, as specified by (args[1],args[2]), (args[3],args[4]), ... etc. returnType = typeScope.ToTable(); int count = args.Length; if ((count & 1) == 0) { errors.EnsureError(DocumentErrorSeverity.Severe, args[0].Parent.CastList().Parent.CastCall(), TexlStrings.ErrBadArityOdd, count); } for (var i = 1; i < count; i += 2) { TexlNode nameArg = args[i]; DType nameArgType = argTypes[i]; // Verify we have a string literal for the column name. Accd to spec, we don't support // arbitrary expressions that evaluate to string values, because these values contribute to // type analysis, so they need to be known upfront (before AddColumns executes). StrLitNode nameNode; if (nameArgType.Kind != DKind.String || (nameNode = nameArg.AsStrLit()) == null) { fArgsValid = false; errors.EnsureError(DocumentErrorSeverity.Severe, nameArg, TexlStrings.ErrExpectedStringLiteralArg_Name, nameArg.ToString()); continue; } // Verify that the name is valid. if (!DName.IsValidDName(nameNode.Value)) { fArgsValid = false; errors.EnsureError(DocumentErrorSeverity.Severe, nameArg, TexlStrings.ErrArgNotAValidIdentifier_Name, nameNode.Value); continue; } DName columnName = new DName(nameNode.Value); string colName; if (DType.TryGetDisplayNameForColumn(typeScope, columnName, out colName)) { columnName = new DName(colName); } // Verify that the name doesn't already exist as either a logical or display name DType columnType; string unused; if (typeScope.TryGetType(columnName, out columnType) || DType.TryGetLogicalNameForColumn(typeScope, columnName, out unused)) { fArgsValid = false; errors.EnsureError(DocumentErrorSeverity.Moderate, nameArg, TexlStrings.ErrColExists_Name, columnName); continue; } if (i + 1 >= count) { break; } columnType = argTypes[i + 1]; // Augment the result type to include the specified column, and verify that it // hasn't been specified already within the same invocation. bool fError = false; returnType = returnType.Add(ref fError, DPath.Root, columnName, columnType); if (fError) { fArgsValid = false; errors.EnsureError(DocumentErrorSeverity.Moderate, nameArg, TexlStrings.ErrColConflict_Name, columnName); continue; } } return(fArgsValid); }
/// <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)); }