private ISignature CreateSignature(ISignatureHelpSession session, IFunctionInfo functionInfo, ISignatureInfo signatureInfo, ITrackingSpan span, AstRoot ast, int position) { SignatureHelp sig = new SignatureHelp(session, _textBuffer, functionInfo.Name, string.Empty, signatureInfo); List <IParameter> paramList = new List <IParameter>(); // Locus points in the pretty printed signature (the one displayed in the tooltip) var locusPoints = new List <int>(); string signatureString = signatureInfo.GetSignatureString(locusPoints); sig.Content = signatureString; sig.ApplicableToSpan = span; sig.Documentation = functionInfo.Description?.Wrap(Math.Min(SignatureInfo.MaxSignatureLength, sig.Content.Length)); Debug.Assert(locusPoints.Count == signatureInfo.Arguments.Count + 1); for (int i = 0; i < signatureInfo.Arguments.Count; i++) { IArgumentInfo p = signatureInfo.Arguments[i]; if (p != null) { int locusStart = locusPoints[i]; int locusLength = locusPoints[i + 1] - locusStart; Debug.Assert(locusLength >= 0); Span locus = new Span(locusStart, locusLength); /// VS may end showing very long tooltip so we need to keep /// description reasonably short: typically about /// same length as the function signature. paramList.Add( new SignatureParameter( p.Description.Wrap( Math.Min(SignatureInfo.MaxSignatureLength, sig.Content.Length)), locus, locus, p.Name, sig)); } } sig.Parameters = new ReadOnlyCollection <IParameter>(paramList); sig.ComputeCurrentParameter(ast, position); return(sig); }
/// <summary> /// Creates formatted signature that is presented to the user /// during function parameter completion. Optionally provides /// locus points (locations withing the string) for each function /// parameter. /// </summary> public string GetSignatureString(List <int> locusPoints = null) { var sb = new StringBuilder(FunctionName); int lineCount = 0; sb.Append('('); if (locusPoints != null) { locusPoints.Add(sb.Length); } for (int i = 0; i < Arguments.Count; i++) { IArgumentInfo arg = Arguments[i]; sb.Append(arg.Name); if (!string.IsNullOrEmpty(arg.DefaultValue)) { sb.Append(" = "); sb.Append(arg.DefaultValue); } if (i < Arguments.Count - 1) { sb.Append(", "); } if (locusPoints != null) { locusPoints.Add(sb.Length); } if (sb.Length > (lineCount + 1) * MaxSignatureLength && i != Arguments.Count - 1) { sb.Append("\r\n"); lineCount++; } } sb.Append(')'); return(sb.ToString()); }
/// <summary> /// Given argument name returns index of the argument in the signature. /// Performs full and then partial matching fof the argument name. /// </summary> /// <param name="argumentName">Name of the argument</param> /// <param name="partialMatch"> /// If true, partial match will be performed /// if exact match is not found /// </param> /// <returns>Argument index or -1 if argumen is not named or was not found</returns> public int GetArgumentIndex(string argumentName, bool partialMatch) { // A function f <- function(foo, bar) is said to have formal parameters "foo" and "bar", // and the call f(foo=3, ba=13) is said to have (actual) arguments "foo" and "ba". // R first matches all arguments that have exactly the same name as a formal parameter. // Two identical argument names cause an error. Then, R matches any argument names that // partially matches a(yet unmatched) formal parameter. But if two argument names partially // match the same formal parameter, that also causes an error. Also, it only matches // formal parameters before .... So formal parameters after ... must be specified using // their full names. Then the unnamed arguments are matched in positional order to // the remaining formal arguments. if (string.IsNullOrEmpty(argumentName)) { return(-1); } // full name match first for (int i = 0; i < Arguments.Count; i++) { IArgumentInfo argInfo = Arguments[i]; if (argInfo.Name.Equals(argumentName, StringComparison.Ordinal)) { return(i); } } if (!partialMatch) { return(-1); } // Try partial match. Only match unique or longest int minLengthDifference = Int32.MaxValue; int index = -1; bool unique = true; for (int i = 0; i < Arguments.Count; i++) { IArgumentInfo argInfo = Arguments[i]; if (argInfo.Name.StartsWith(argumentName, StringComparison.Ordinal)) { int lengthDifference = argInfo.Name.Length - argumentName.Length; if (lengthDifference < minLengthDifference) { minLengthDifference = lengthDifference; index = i; unique = true; } else if (index >= 0) { unique = false; } } if (argInfo.IsEllipsis) { break; } } return(unique ? index : -1); }
internal GeneratorError(IArgumentInfo argumentInfo, GeneratorErrorType generatorErrorType) { this.Type = generatorErrorType; this.ArgumentInfo = argumentInfo; }
internal GeneratorError(IArgumentInfo argumentInfo, GeneratorError innerGeneratorError) { this.Type = GeneratorErrorType.InnerGeneratorError; this.ArgumentInfo = argumentInfo; this.InnerGeneratorError = innerGeneratorError; }
private static bool ParameterNameMatches(IArgumentInfo argument, string propertyName) { return(argument.MatchingParameter != null && string.Compare(argument.MatchingParameter.Element.ShortName, propertyName, StringComparison.InvariantCultureIgnoreCase) == 0); }