示例#1
0
        public static bool FindCurFuncAndArgs(TexlNode curNode, int cursorPos, TexlBinding binding, out TexlFunction curFunc, out int argIndex, out int argCount, out DType expectedType)
        {
            Contracts.AssertValue(curNode);
            Contracts.AssertValue(binding);

            if (curNode.Kind == NodeKind.Call)
            {
                CallNode callNode = curNode.CastCall();
                if (callNode.Token.Span.Lim <= cursorPos && callNode.ParenClose != null && cursorPos <= callNode.ParenClose.Span.Min)
                {
                    CallInfo info = binding.GetInfo(callNode);

                    if (info.Function != null)
                    {
                        curFunc      = info.Function;
                        argIndex     = 0;
                        argCount     = callNode.Args.Count;
                        expectedType = curFunc.ParamTypes.Length > 0 ? curFunc.ParamTypes[0] : DType.Error;

                        return(true);
                    }
                }
            }

            if (IntellisenseHelper.TryGetInnerMostFunction(curNode, binding, out curFunc, out argIndex, out argCount))
            {
                expectedType = curFunc.ParamTypes.Length > argIndex ? curFunc.ParamTypes[argIndex] : DType.Error;
                return(true);
            }

            expectedType = DType.Error;
            return(false);
        }
            internal override bool TryAddSuggestionsForNodeKind(IntellisenseData.IntellisenseData intellisenseData)
            {
                Contracts.AssertValue(intellisenseData);

                TexlNode curNode   = intellisenseData.CurNode;
                int      cursorPos = intellisenseData.CursorPos;

                CallNode callNode = curNode.CastCall();
                int      spanMin  = callNode.Head.Token.Span.Min;
                int      spanLim  = callNode.Head.Token.Span.Lim;

                // Handling the special case for service functions with non-empty namespaces.
                // We have to consider the namespace as the begining of the callNode for intellisense purposes.
                if (callNode.HeadNode != null)
                {
                    var dottedNode = callNode.HeadNode.AsDottedName();
                    spanMin = dottedNode.Left.Token.Span.Min;
                    spanLim = dottedNode.Right.Token.Span.Lim;
                }

                if (cursorPos < spanMin)
                {
                    // Cursor is before the head
                    // i.e. "| Filter(....)"
                    // Suggest possibilities that can result in a value.
                    IntellisenseHelper.AddSuggestionsForValuePossibilities(intellisenseData, callNode);
                }
                else if (cursorPos <= spanLim)
                {
                    // Cursor is in the head.
                    // Suggest function names.
                    // Get the matching string as a substring from the script so that the whitespace is preserved.
                    int replacementLength = IntellisenseHelper.GetReplacementLength(intellisenseData, spanMin, spanLim, intellisenseData.Binding.NameResolver.Functions.Select(function => function.Name));

                    // If we are replacing the full token, also include the opening paren (since this will be provided by the suggestion)
                    if (replacementLength == spanLim - spanMin)
                    {
                        replacementLength += TexlLexer.PunctuatorParenOpen.Length;
                    }

                    intellisenseData.SetMatchArea(spanMin, cursorPos, replacementLength);
                    intellisenseData.BoundTo = intellisenseData.Binding.ErrorContainer.HasErrors(callNode) ? string.Empty : callNode.Head.Name;
                    IntellisenseHelper.AddSuggestionsForFunctions(intellisenseData);
                }
                else if (callNode.Token.Span.Lim > cursorPos || callNode.ParenClose == null)
                {
                    // Handling the erroneous case when user enters a space after functionName and cursor is after space.
                    // Cursor is before the open paren of the function.
                    // Eg: "Filter | (" AND "Filter | (some Table, some predicate)"
                    return(false);
                }
                else
                {
                    // If there was no closed parenthesis we would have an error node.
                    Contracts.Assert(callNode.ParenClose != null);

                    if (cursorPos <= callNode.ParenClose.Span.Min)
                    {
                        // Cursor position is before the closed parenthesis and there are no arguments.
                        // If there were arguments FindNode should have returned one of those.
                        if (intellisenseData.CurFunc != null && intellisenseData.CurFunc.MaxArity > 0)
                        {
                            IntellisenseHelper.AddSuggestionsForTopLevel(intellisenseData, callNode);
                        }
                    }
                    else if (IntellisenseHelper.CanSuggestAfterValue(cursorPos, intellisenseData.Script))
                    {
                        // Verify that cursor is after a space after the closed parenthesis and
                        // suggest binary operators.
                        IntellisenseHelper.AddSuggestionsForAfterValue(intellisenseData, intellisenseData.Binding.GetType(callNode));
                    }
                }

                return(true);
            }