/// <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;
            }
        }
Example #3
0
        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;
            }
        }