/// <summary> /// Generates completion options for a manager script. /// </summary> /// <param name="code">Source code.</param> /// <param name="offset">Offset of the cursor/caret in the source code.</param> /// <param name="controlSpace">True iff this intellisense request was generated by the user pressing control + space.</param> /// <returns>True if any completion options are found. False otherwise.</returns> public bool GenerateScriptCompletions(string code, int offset, bool controlSpace = false) { CSharpParser parser = new CSharpParser(); SyntaxTree syntaxTree = parser.Parse(code); string fileName = Path.GetTempFileName(); if (!File.Exists(fileName)) { File.Create(fileName).Close(); } File.WriteAllText(fileName, code); syntaxTree.FileName = fileName; syntaxTree.Freeze(); // Should probably take into account which namespaces the user is using and load the needed assemblies into the CSharpCompletion object // string usings = syntaxTree.Descendants.OfType<UsingDeclaration>().Select(x => x.ToString()).Aggregate((x, y) => x + /* Environment.NewLine + */ y); IDocument document = new ReadOnlyDocument(new StringTextSource(code), syntaxTree.FileName); completionResult = completion.GetCompletions(document, offset, controlSpace); // Set the trigger word for later use. triggerWord = controlSpace ? completionResult.TriggerWord : string.Empty; // If the user pressed control space, we assume they are trying to generate completions for a partially typed word. // In this situation we need to filter the results based on what they have already typed. // The exception is if the most recent character is a period. // No idea why NRefactory can't do this for us. if (controlSpace && !string.IsNullOrEmpty(completionResult.TriggerWord) && code[offset - 1] != '.') { // Filter items. completionResult.CompletionData = completionResult.CompletionData.Where(item => GetMatchQuality(item.CompletionText, completionResult.TriggerWord) > 0).ToList(); } List <CompletionData> completionList = completionResult.CompletionData.Select(x => x as CompletionData).Where(x => x != null).OrderBy(x => x.CompletionText).ToList(); view.Populate(completionList); if (controlSpace && !string.IsNullOrEmpty(completionResult.TriggerWord)) { view.SelectItem(completionList.IndexOf(completionList.OrderByDescending(x => GetMatchQuality(x.CompletionText, completionResult.TriggerWord)).FirstOrDefault())); } return(completionList.Any()); }
/// <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; } }
private void ShowCompletion(string enteredText, bool controlSpace) { if (!controlSpace) { Debug.WriteLine("Code Completion: TextEntered: " + enteredText); } else { Debug.WriteLine("Code Completion: Ctrl+Space"); } //only process csharp files if (String.IsNullOrEmpty(textEditor.Document.FileName)) { return; } var fileExtension = Path.GetExtension(textEditor.Document.FileName); fileExtension = fileExtension != null?fileExtension.ToLower() : null; //check file extension to be a c# file (.cs, .csx, etc.) if (fileExtension == null || (!fileExtension.StartsWith(".cs"))) { return; } if (completionWindow == null) { CodeCompletionResult results = null; try { results = CSharpCompletion.GetCompletions(textEditor.Document, textEditor.CaretOffset, controlSpace); } catch (Exception exception) { Debug.WriteLine("Error in getting completion: " + exception); } if (results == null) { return; } if (insightWindow == null && results.OverloadProvider != null) { insightWindow = new OverloadInsightWindow(textEditor.TextArea); insightWindow.Provider = results.OverloadProvider; insightWindow.Show(); insightWindow.Closed += (o, args) => insightWindow = null; return; } if (completionWindow == null && results != null && results.CompletionData.Any()) { // Open code completion after the user has pressed dot: completionWindow = new CompletionWindow(textEditor.TextArea); completionWindow.CloseWhenCaretAtBeginning = controlSpace; completionWindow.StartOffset -= results.TriggerWordLength; //completionWindow.EndOffset -= results.TriggerWordLength; IList <ICompletionData> data = completionWindow.CompletionList.CompletionData; foreach (var completion in results.CompletionData.OrderBy(item => item.Text)) { data.Add(completion); } if (results.TriggerWordLength > 0) { //completionWindow.CompletionList.IsFiltering = false; completionWindow.CompletionList.SelectItem(results.TriggerWord); } completionWindow.Show(); completionWindow.Closed += (o, args) => completionWindow = null; } }//end if //update the insight window if (!string.IsNullOrEmpty(enteredText) && insightWindow != null) { //whenver text is entered update the provider var provider = insightWindow.Provider as CSharpOverloadProvider; if (provider != null) { //since the text has not been added yet we need to tread it as if the char has already been inserted provider.Update(textEditor.Document, textEditor.CaretOffset); //if the windows is requested to be closed we do it here if (provider.RequestClose) { insightWindow.Close(); insightWindow = null; } } } }//end method
public CodeCompletionResult GetCompletions(IDocument document, int offset, bool controlSpace = false, string[] namespaces = null) { var result = new CodeCompletionResult(); if (String.IsNullOrEmpty(document.FileName)) return result; var completionContext = new CSharpCompletionContext(document, offset, projectContent, namespaces); var completionFactory = new CSharpCompletionDataFactory(completionContext.TypeResolveContextAtCaret, completionContext); var cce = new CSharpCompletionEngine( completionContext.Document, completionContext.CompletionContextProvider, completionFactory, completionContext.ProjectContent, completionContext.TypeResolveContextAtCaret ); cce.EolMarker = Environment.NewLine; cce.FormattingPolicy = FormattingOptionsFactory.CreateSharpDevelop(); var completionChar = completionContext.Document.GetCharAt(completionContext.Offset - 1); int startPos, triggerWordLength; IEnumerable<ICSharpCode.NRefactory.Completion.ICompletionData> completionData; if (controlSpace) { if (!cce.TryGetCompletionWord(completionContext.Offset, out startPos, out triggerWordLength)) { startPos = completionContext.Offset; triggerWordLength = 0; } completionData = cce.GetCompletionData(startPos, true); //this outputs tons of available entities //if (triggerWordLength == 0) // completionData = completionData.Concat(cce.GetImportCompletionData(startPos)); } else { startPos = completionContext.Offset; if (char.IsLetterOrDigit(completionChar) || completionChar == '_') { if (startPos > 1 && char.IsLetterOrDigit(completionContext.Document.GetCharAt(startPos - 2))) return result; completionData = cce.GetCompletionData(startPos, false); startPos--; triggerWordLength = 1; } else { completionData = cce.GetCompletionData(startPos, false); triggerWordLength = 0; } } result.TriggerWordLength = triggerWordLength; result.TriggerWord = completionContext.Document.GetText(completionContext.Offset - triggerWordLength, triggerWordLength); Debug.Print("Trigger word: '{0}'", result.TriggerWord); //cast to AvalonEdit completion data and add to results foreach (var completion in completionData) { var cshellCompletionData = completion as CompletionData; if (cshellCompletionData != null) { cshellCompletionData.TriggerWord = result.TriggerWord; cshellCompletionData.TriggerWordLength = result.TriggerWordLength; result.CompletionData.Add(cshellCompletionData); } } //method completions if (!controlSpace) { // Method Insight var pce = new CSharpParameterCompletionEngine( completionContext.Document, completionContext.CompletionContextProvider, completionFactory, completionContext.ProjectContent, completionContext.TypeResolveContextAtCaret ); var parameterDataProvider = pce.GetParameterDataProvider(completionContext.Offset, completionChar); result.OverloadProvider = parameterDataProvider as IOverloadProvider; } return result; }
public static void SetCodeCompletionOptions(IEnumerable <CodeCompletionResult> codeCompletionResults, CodeCompletionResult itemToSelect) // string completionWord = null) { var orderedResults = codeCompletionResults.OrderBy(x => x.CompletionText).ToArray(); _CodeCompletionOptions.Clear(); foreach (var x in orderedResults) { _CodeCompletionOptions.Add(x); } if (itemToSelect != null) { _CodeCompletionListView.ScrollIntoView(itemToSelect); _CodeCompletionListView.SelectedItem = itemToSelect; } }