/// <summary> /// Updates the view. Typically called after the user cycles through the /// available method overloads. /// </summary> private void Refresh() { MethodCompletion completion = completions[visibleCompletionIndex]; lblMethodSignature.Text = completion.Signature; lblMethodSummary.Text = completion.Summary; // For each line in the argument summaries, we need to make the argument name bold. // We can do this by putting it inside html <b></b> tags. To get the name by itself, // we look for all text between the start of a line and the first colon : on that line. // This makes a lot of assumptions about how the data is formatted by the presenter, // but it's good enough for now. lblArgumentSummaries.Markup = System.Text.RegularExpressions.Regex.Replace(completion.ParameterDocumentation, @"^([^:]+:)", @"<b>$1</b>", System.Text.RegularExpressions.RegexOptions.Multiline); lblArgumentSummaries.WidthChars = Math.Max(completion.Signature.Length, completion.Summary.Length); lblOverloadIndex.Text = string.Format("{0} of {1}", visibleCompletionIndex + 1, completions.Count); }
/// <summary> /// Shows completion information for a method call. /// </summary> /// <param name="relativeTo">Model to be used as a reference when searching for completion data.</param> /// <param name="code">Code for which we want to generate completion data.</param> /// <param name="offset">Offset of the cursor/caret in the code.</param> public void ShowMethodCompletion(IModel relativeTo, string code, int offset, Point location) { string contentsToCursor = code.Substring(0, offset).TrimEnd('.'); // Ignore everything before the most recent comma. contentsToCursor = contentsToCursor.Substring(contentsToCursor.LastIndexOf(',') + 1); string currentLine = contentsToCursor.Split(Environment.NewLine.ToCharArray()).Last().Trim(); // Set the trigger word for later use. triggerWord = GetTriggerWord(currentLine); // Ignore everything before most recent model name in square brackets. // I'm assuming that model/node names cannot start with a number. string modelNamePattern = @"\[([A-Za-z]+[A-Za-z0-9]*)\]"; string objectName = currentLine; var matches = System.Text.RegularExpressions.Regex.Matches(code, modelNamePattern); if (matches.Count > 0) { int modelNameIndex = currentLine.LastIndexOf(matches[matches.Count - 1].Value); if (modelNameIndex >= 0) { currentLine = currentLine.Substring(modelNameIndex); int lastPeriod = currentLine.LastIndexOf('.'); objectName = lastPeriod >= 0 ? currentLine.Substring(0, lastPeriod) : currentLine; } } string methodName = triggerWord.TrimEnd('('); MethodInfo method = NeedContextItemsArgs.GetMethodInfo(relativeTo as Model, methodName, objectName); if (method == null) { return; } MethodCompletion completion = new MethodCompletion(); List <string> parameterStrings = new List <string>(); StringBuilder parameterDocumentation = new StringBuilder(); foreach (ParameterInfo parameter in method.GetParameters()) { string parameterString = string.Format("{0} {1}", parameter.ParameterType.Name, parameter.Name); if (parameter.DefaultValue != DBNull.Value) { parameterString += string.Format(" = {0}", parameter.DefaultValue.ToString()); } parameterStrings.Add(parameterString); parameterDocumentation.AppendLine(string.Format("{0}: {1}", parameter.Name, NeedContextItemsArgs.GetDescription(method, parameter.Name))); } string parameters = parameterStrings.Aggregate((a, b) => string.Format("{0}, {1}", a, b)); completion.Signature = string.Format("{0} {1}({2})", method.ReturnType.Name, method.Name, parameters); completion.Summary = NeedContextItemsArgs.GetDescription(method); completion.ParameterDocumentation = parameterDocumentation.ToString().Trim(Environment.NewLine.ToCharArray()); methodCompletionView.Completions = new List <MethodCompletion>() { completion }; methodCompletionView.Location = location; methodCompletionView.Visible = true; }
/// <summary> /// Shows completion information for a method call. /// </summary> /// <param name="relativeTo">Model to be used as a reference when searching for completion data.</param> /// <param name="code">Code for which we want to generate completion data.</param> /// <param name="offset">Offset of the cursor/caret in the code.</param> public void ShowScriptMethodCompletion(IModel relativeTo, string code, int offset, Point location) { CSharpParser parser = new CSharpParser(); SyntaxTree syntaxTree = parser.Parse(code); string fileName = Path.GetTempFileName(); File.WriteAllText(fileName, code); syntaxTree.FileName = fileName; syntaxTree.Freeze(); IDocument document = new ReadOnlyDocument(new StringTextSource(code), syntaxTree.FileName); CodeCompletionResult result = completion.GetMethodCompletion(document, offset, false); File.Delete(fileName); if (result.OverloadProvider != null) { if (result.OverloadProvider.Count < 1) { return; } List <MethodCompletion> completions = new List <MethodCompletion>(); foreach (IParameterizedMember method in result.OverloadProvider.Items.Select(x => x.Method)) { // Generate argument signatures - e.g. string foo, int bar List <string> arguments = new List <string>(); foreach (var parameter in method.Parameters) { string parameterString = string.Format("{0} {1}", parameter.Type.Name, parameter.Name); if (parameter.ConstantValue != null) { parameterString += string.Format(" = {0}", parameter.ConstantValue.ToString()); } arguments.Add(parameterString); } MethodCompletion completion = new MethodCompletion() { Signature = string.Format("{0} {1}({2})", method.ReturnType.Name, method.Name, arguments.Any() ? arguments.Aggregate((x, y) => string.Format("{0}, {1}", x, y)) : string.Empty) }; if (method.Documentation == null) { completion.Summary = string.Empty; completion.ParameterDocumentation = string.Empty; } else { if (method.Documentation.Xml.Text.Contains("<summary>") && method.Documentation.Xml.Text.Contains("</summary>")) { completion.Summary = method.Documentation.Xml.Text.Substring(0, method.Documentation.Xml.Text.IndexOf("</summary")).Replace("<summary>", string.Empty).Trim(Environment.NewLine.ToCharArray()).Trim(); } else { completion.Summary = string.Empty; } // NRefactory doesn't do anything more than read the xml documentation file. // Therefore, we need to parse this XML to get the parameter summaries. XmlDocument doc = new XmlDocument(); doc.LoadXml(string.Format("<documentation>{0}</documentation>", method.Documentation.Xml.Text)); List <string> argumentSummariesList = new List <string>(); foreach (XmlElement parameter in XmlUtilities.ChildNodesRecursively(doc.FirstChild, "param")) { argumentSummariesList.Add(string.Format("{0}: {1}", parameter.GetAttribute("name"), parameter.InnerText)); } if (argumentSummariesList.Any()) { completion.ParameterDocumentation = argumentSummariesList.Aggregate((x, y) => x + Environment.NewLine + y); } else { completion.ParameterDocumentation = string.Empty; } } completions.Add(completion); } methodCompletionView.Completions = completions; methodCompletionView.Location = location; methodCompletionView.Visible = true; } }