예제 #1
0
        private IEnumerable <CompletionResult> MakeSnippetedResponses(CompletionRequest request, ISymbol symbol)
        {
            var completions  = new List <CompletionResult>();
            var methodSymbol = symbol as IMethodSymbol;

            if (methodSymbol != null)
            {
                if (methodSymbol.Parameters.Any(p => p.IsOptional))
                {
                    completions.Add(MakeAutoCompleteResponse(request, symbol, false));
                }
                completions.Add(MakeAutoCompleteResponse(request, symbol));
                return(completions);
            }
            var typeSymbol = symbol as INamedTypeSymbol;

            if (typeSymbol != null)
            {
                completions.Add(MakeAutoCompleteResponse(request, symbol));

                if (typeSymbol.TypeKind != TypeKind.Enum)
                {
                    foreach (var ctor in typeSymbol.InstanceConstructors)
                    {
                        completions.Add(MakeAutoCompleteResponse(request, ctor));
                    }
                }
                return(completions);
            }
            return(new[] { MakeAutoCompleteResponse(request, symbol) });
        }
예제 #2
0
        private CompletionResult MakeAutoCompleteResponse(CompletionRequest request, ISymbol symbol, bool includeOptionalParams = true)
        {
            var displayNameGenerator = new SnippetGenerator();

            displayNameGenerator.IncludeMarkers            = false;
            displayNameGenerator.IncludeOptionalParameters = includeOptionalParams;

            var response = new CompletionResult();

            response.CompletionText = symbol.Name;

            if (request.WantKind)
            {
                response.Kind = symbol.GetKind();
            }

            // Handle special case for constructors.
            var methodSymbol = symbol as IMethodSymbol;

            if (methodSymbol?.MethodKind == MethodKind.Constructor)
            {
                response.CompletionText = methodSymbol.ContainingType.Name;

                if (request.WantKind)
                {
                    response.Kind = "Class";
                }
            }

            // TODO: Do something more intelligent here
            response.DisplayText = displayNameGenerator.Generate(symbol);

            if (request.WantDocumentationForEveryCompletionResult)
            {
                response.Description = DocumentationConverter.ConvertDocumentation(symbol.GetDocumentationCommentXml(), "\n");
            }

            if (request.WantReturnType)
            {
                response.ReturnType = ReturnTypeFormatter.GetReturnType(symbol);
            }

            if (request.WantSnippet)
            {
                var snippetGenerator = new SnippetGenerator();
                snippetGenerator.IncludeMarkers            = true;
                snippetGenerator.IncludeOptionalParameters = includeOptionalParams;
                response.Snippet = snippetGenerator.Generate(symbol);
            }

            if (request.WantMethodHeader)
            {
                response.MethodHeader = displayNameGenerator.Generate(symbol);
            }

            return(response);
        }
예제 #3
0
        public async Task <CompletionResult[]> GetCompletionsAsync(CompletionRequest request, string code)
        {
            var workspace    = new AdhocWorkspace();
            var projectName  = RandomString(6, "Project");
            var assemblyName = RandomString(6, "Assembly");
            var documentName = RandomString(6, "Document");
            var project      = workspace.CurrentSolution.AddProject(projectName, assemblyName, LanguageNames.CSharp);

            // We need to reference assemblies that the code relies on.
            var references = GetMetadataReferences();

            project = project.WithMetadataReferences(references);

            var document = project.AddDocument(documentName, SourceText.From(code));

            var text = await document.GetTextAsync();

            var position = text.Lines.GetPosition(new LinePosition(request.Line, request.Character));
            var model    = await document.GetSemanticModelAsync();

            var completions = new List <CompletionResult>();

            AddKeywords(workspace, completions, model, position, request.WantKind, request.WordToComplete);

            var symbols = Recommender.GetRecommendedSymbolsAtPosition(model, position, workspace);

            foreach (var symbol in symbols.Where(s => s.Name.IsValidCompletionFor(request.WordToComplete)))
            {
                if (request.WantSnippet)
                {
                    foreach (var completion in MakeSnippetedResponses(request, symbol))
                    {
                        completions.Add(completion);
                    }
                }
                else
                {
                    completions.Add(MakeAutoCompleteResponse(request, symbol));
                }
            }

            return(completions
                   .OrderByDescending(c => c.CompletionText.IsValidCompletionStartsWithExactCase(request.WordToComplete))
                   .ThenByDescending(c => c.CompletionText.IsValidCompletionStartsWithIgnoreCase(request.WordToComplete))
                   .ThenByDescending(c => c.CompletionText.IsCamelCaseMatch(request.WordToComplete))
                   .ThenByDescending(c => c.CompletionText.IsSubsequenceMatch(request.WordToComplete))
                   .ThenBy(c => c.CompletionText)
                   .ToArray());
        }
예제 #4
0
        public async Task <CompletionResult[]> GetCompletionsAsync(CompletionRequest request, Source source)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            // We need to ensure all dependencies have been downloaded and located. ResolveReferences() gets a
            // firm reference for each reference and any additional dependencies.
            var references          = _metadataProvider.ResolveReferences(source.Dependencies);
            var referenceAssemblies = references.Select(r => Assembly.LoadFrom(r.Display)).ToArray();

            var compositionContext = new ContainerConfiguration()
                                     .WithAssemblies(MefHostServices.DefaultAssemblies
                                                     .Concat(new[]
            {
                // These assemblies are necessary to enable language services.
                Assembly.Load("Microsoft.CodeAnalysis.Features"),
                Assembly.Load("Microsoft.CodeAnalysis.CSharp.Features")
            })
                                                     .Concat(referenceAssemblies))
                                     .CreateContainer();

            var host = MefHostServices.Create(compositionContext);

            // Setup a workspace for this code file, since we aren't actively managing a project or solutions.
            var workspace    = new AdhocWorkspace(host);
            var projectName  = RandomString(6, "Project");
            var assemblyName = RandomString(6, "Assembly");
            var documentName = RandomString(6, "Document");

            var document = workspace.CurrentSolution
                           .AddProject(projectName, assemblyName, LanguageNames.CSharp)
                           .WithMetadataReferences(references)
                           .AddDocument(documentName, SourceText.From(source.Code));

            // Determine position of cursor so we know which symbols to recommend.
            var text = await document.GetTextAsync();

            var position = text.Lines.GetPosition(new LinePosition(request.Line, request.Character));

            // The code analysis libraries have rolled in all the intellisense code
            // so all we need to do is get a reference to the CompletionService and
            // request completions for the given character position.
            var service     = CompletionService.GetService(document);
            var completions = await service.GetCompletionsAsync(document, position);

            var completionResults = new List <CompletionResult>();

            // We'll handle special cases for keywords, and determine whether the
            // completions we received are valid for the given text position.
            if (completions != null)
            {
                foreach (var item in completions.Items)
                {
                    if (item.Tags.Contains(CompletionTags.Keyword))
                    {
                        // For keywords we'll assume the completion text is the same as the display text.
                        var keyword = item.DisplayText;

                        if (keyword.IsValidCompletionFor(request.WordToComplete))
                        {
                            var response = new CompletionResult()
                            {
                                CompletionText = item.DisplayText,
                                DisplayText    = item.DisplayText,
                                Snippet        = item.DisplayText,
                                Kind           = request.WantKind ? "Keyword" : null
                            };

                            completionResults.Add(response);
                        }
                    }
                }
            }

            // Now we'll add completions based on the semantics model and referenced assemblies.
            var model = await document.GetSemanticModelAsync();

            var symbols = await Recommender.GetRecommendedSymbolsAtPositionAsync(model, position, workspace);

            foreach (var symbol in symbols.Where(s => s.Name.IsValidCompletionFor(request.WordToComplete)))
            {
                if (request.WantSnippet)
                {
                    foreach (var completion in MakeSnippetedResponses(request, symbol))
                    {
                        completionResults.Add(completion);
                    }
                }
                else
                {
                    completionResults.Add(MakeAutoCompleteResponse(request, symbol));
                }
            }

            // Order the list to the most appropriate completions first.
            return(completionResults
                   .OrderByDescending(c => c.CompletionText.IsValidCompletionStartsWithExactCase(request.WordToComplete))
                   .ThenByDescending(c => c.CompletionText.IsValidCompletionStartsWithIgnoreCase(request.WordToComplete))
                   .ThenByDescending(c => c.CompletionText.IsCamelCaseMatch(request.WordToComplete))
                   .ThenByDescending(c => c.CompletionText.IsSubsequenceMatch(request.WordToComplete))
                   .ThenBy(c => c.CompletionText)
                   .ToArray());
        }