From 87c13a38a48d1afa7342e7d795b9f6a0d494d3a5 Mon Sep 17 00:00:00 2001 From: filipw Date: Mon, 1 May 2017 11:07:00 +0200 Subject: [PATCH 01/11] removed suppressing CS1024 in scripts --- .../Workers/Diagnostics/CSharpDiagnosticService.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/OmniSharp.Roslyn.CSharp/Workers/Diagnostics/CSharpDiagnosticService.cs b/src/OmniSharp.Roslyn.CSharp/Workers/Diagnostics/CSharpDiagnosticService.cs index 3ff8e77a74..190402c5e3 100644 --- a/src/OmniSharp.Roslyn.CSharp/Workers/Diagnostics/CSharpDiagnosticService.cs +++ b/src/OmniSharp.Roslyn.CSharp/Workers/Diagnostics/CSharpDiagnosticService.cs @@ -148,13 +148,6 @@ private async Task ProcessNextItem(string filePath) var semanticModel = await document.GetSemanticModelAsync(); IEnumerable diagnostics = semanticModel.GetDiagnostics(); - //script files can have custom directives such as #load which will be deemed invalid by Roslyn - //we suppress the CS1024 diagnostic for script files for this reason. Roslyn will fix it later too, so this is temporary. - if (document.SourceCodeKind != SourceCodeKind.Regular) - { - diagnostics = diagnostics.Where(diagnostic => diagnostic.Id != "CS1024"); - } - foreach (var quickFix in diagnostics.Select(MakeQuickFix)) { var existingQuickFix = items.FirstOrDefault(q => q.Equals(quickFix)); From dbdc7132f7c173d284aeaddf1429d84e3afdcbe0 Mon Sep 17 00:00:00 2001 From: filipw Date: Sun, 30 Apr 2017 12:27:32 +0200 Subject: [PATCH 02/11] first stab at improving IntellisenseService --- .../Intellisense/IntellisenseService.cs | 6 +- .../Intellisense/IntellisenseV2Service.cs | 226 ++++++++++++++++++ 2 files changed, 229 insertions(+), 3 deletions(-) create mode 100644 src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseV2Service.cs diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs index 292bf8141e..d57f1ec6b7 100644 --- a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs +++ b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs @@ -14,14 +14,14 @@ namespace OmniSharp.Roslyn.CSharp.Services.Intellisense { - [OmniSharpHandler(OmniSharpEndpoints.AutoComplete, LanguageNames.CSharp)] - public class IntellisenseService : IRequestHandler> + //[OmniSharpHandler(OmniSharpEndpoints.AutoComplete, LanguageNames.CSharp)] + public class IntellisenseOldService : IRequestHandler> { private readonly OmniSharpWorkspace _workspace; private readonly FormattingOptions _formattingOptions; [ImportingConstructor] - public IntellisenseService(OmniSharpWorkspace workspace, FormattingOptions formattingOptions) + public IntellisenseOldService(OmniSharpWorkspace workspace, FormattingOptions formattingOptions) { _workspace = workspace; _formattingOptions = formattingOptions; diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseV2Service.cs b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseV2Service.cs new file mode 100644 index 0000000000..4c9e385f2f --- /dev/null +++ b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseV2Service.cs @@ -0,0 +1,226 @@ +using System.Collections.Generic; +using System.Composition; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.Text; +using OmniSharp.Extensions; +using OmniSharp.Mef; +using OmniSharp.Models.AutoComplete; +using OmniSharp.Options; +using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis.Options; +using System.Reflection; +using System.Threading; +using System.Collections.Immutable; +using OmniSharp.Roslyn.CSharp.Services.Documentation; +using Microsoft.CodeAnalysis.Recommendations; + +namespace OmniSharp.Roslyn.CSharp.Services.Intellisense +{ + [OmniSharpHandler(OmniSharpEndpoints.AutoComplete, LanguageNames.CSharp)] + public class IntellisenseService : IRequestHandler> + { + private readonly OmniSharpWorkspace _workspace; + private readonly FormattingOptions _formattingOptions; + + [ImportingConstructor] + public IntellisenseService(OmniSharpWorkspace workspace, FormattingOptions formattingOptions) + { + _workspace = workspace; + _formattingOptions = formattingOptions; + } + + public async Task> Handle(AutoCompleteRequest request) + { + var documents = _workspace.GetDocuments(request.FileName); + var wordToComplete = request.WordToComplete; + var completions = new HashSet(); + + foreach (var document in documents) + { + var sourceText = await document.GetTextAsync(); + var position = sourceText.Lines.GetPosition(new LinePosition(request.Line, request.Column)); + + //var options = await document.GetOptionsAsync(); + //options.WithChangedOption(new PerLanguageOption("CompletionOptions", "SnippetsBehavior", SnippetsRule.AlwaysInclude), LanguageNames.CSharp, SnippetsRule.AlwaysInclude); + //options.WithChangedOption() + var semanticModel = await document.GetSemanticModelAsync(); + var service = CompletionService.GetService(document); + var completionList = await service.GetCompletionsAsync(document, position); + //options: options.WithChangedOption(new PerLanguageOption("CompletionOptions", "SnippetsBehavior", SnippetsRule.AlwaysInclude))); + + // Add keywords from the completion list. We'll use the recommender service to get symbols + // to create snippets from. + + + var recommendedSymbols = await Recommender.GetRecommendedSymbolsAtPositionAsync(semanticModel, position, _workspace); + + if (completionList != null) + { + foreach (var item in completionList.Items) + { + //if (item.Tags.Contains(CompletionTags.Keyword)) + { + // Note: For keywords, we'll just assume that the completion text is the same + // as the display text. + var keyword = item.DisplayText; + if (keyword.IsValidCompletionFor(wordToComplete)) + { + if (item.Properties.ContainsKey("Provider") && item.Properties["Provider"] == "Microsoft.CodeAnalysis.CSharp.Completion.Providers.SymbolCompletionProvider") + { + //var symbolsTask = GetSymbolsAsync.Invoke(null, new object[] { item, document, default(CancellationToken) }) as Task>; + //var symbols = await symbolsTask; + //SymbolFinder. + //foreach (var symbol in symbols.Where(s => s.Name.IsValidCompletionFor(wordToComplete))) + //service.GetDescriptionAsync + { + var symbols = recommendedSymbols.Where(x => x.Name == item.Properties["SymbolName"] && (int)x.Kind == int.Parse(item.Properties["SymbolKind"])).Distinct(); + + if (symbols != null && symbols.Any()) + { + foreach (var symbol in symbols) + { + if (symbol != null) + { + if (request.WantSnippet) + { + foreach (var completion in MakeSnippetedResponses(request, symbol)) + { + completions.Add(completion); + } + } + else + { + completions.Add(MakeAutoCompleteResponse(request, symbol)); + } + } + } + + continue; + } + } + } + + var response = new AutoCompleteResponse() + { + CompletionText = item.DisplayText, + DisplayText = item.DisplayText, + Snippet = item.DisplayText, + Kind = request.WantKind ? item.Tags.First() : null + }; + + completions.Add(response); + } + } + } + } + + //var model = await document.GetSemanticModelAsync(); + //var symbols = await Recommender.GetRecommendedSymbolsAtPositionAsync(model, position, _workspace); + + //foreach (var symbol in symbols.Where(s => s.Name.IsValidCompletionFor(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(wordToComplete)) + .ThenByDescending(c => c.CompletionText.IsValidCompletionStartsWithIgnoreCase(wordToComplete)) + .ThenByDescending(c => c.CompletionText.IsCamelCaseMatch(wordToComplete)) + .ThenByDescending(c => c.CompletionText.IsSubsequenceMatch(wordToComplete)) + .ThenBy(c => c.CompletionText); + } + + private IEnumerable MakeSnippetedResponses(AutoCompleteRequest request, ISymbol symbol) + { + var completions = new List(); + + 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) }; + } + + private AutoCompleteResponse MakeAutoCompleteResponse(AutoCompleteRequest request, ISymbol symbol, bool includeOptionalParams = true) + { + var displayNameGenerator = new SnippetGenerator(); + displayNameGenerator.IncludeMarkers = false; + displayNameGenerator.IncludeOptionalParameters = includeOptionalParams; + + var response = new AutoCompleteResponse(); + response.CompletionText = symbol.Name; + + // TODO: Do something more intelligent here + response.DisplayText = displayNameGenerator.Generate(symbol); + + if (request.WantDocumentationForEveryCompletionResult) + { + response.Description = DocumentationConverter.ConvertDocumentation(symbol.GetDocumentationCommentXml(), _formattingOptions.NewLine); + } + + if (request.WantReturnType) + { + response.ReturnType = ReturnTypeFormatter.GetReturnType(symbol); + } + + if (request.WantKind) + { + response.Kind = symbol.GetKind(); + } + + 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; + } + } +} From 8f233f05991f248e9b15498177f225c3378cdee8 Mon Sep 17 00:00:00 2001 From: filipw Date: Sun, 30 Apr 2017 12:28:28 +0200 Subject: [PATCH 03/11] remved IntellisenseV2Service --- .../Intellisense/IntellisenseService.cs | 87 +++++-- .../Intellisense/IntellisenseV2Service.cs | 226 ------------------ 2 files changed, 65 insertions(+), 248 deletions(-) delete mode 100644 src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseV2Service.cs diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs index d57f1ec6b7..65638aadc5 100644 --- a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs +++ b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs @@ -14,14 +14,14 @@ namespace OmniSharp.Roslyn.CSharp.Services.Intellisense { - //[OmniSharpHandler(OmniSharpEndpoints.AutoComplete, LanguageNames.CSharp)] - public class IntellisenseOldService : IRequestHandler> + [OmniSharpHandler(OmniSharpEndpoints.AutoComplete, LanguageNames.CSharp)] + public class IntellisenseService : IRequestHandler> { private readonly OmniSharpWorkspace _workspace; private readonly FormattingOptions _formattingOptions; [ImportingConstructor] - public IntellisenseOldService(OmniSharpWorkspace workspace, FormattingOptions formattingOptions) + public IntellisenseService(OmniSharpWorkspace workspace, FormattingOptions formattingOptions) { _workspace = workspace; _formattingOptions = formattingOptions; @@ -38,29 +38,72 @@ public async Task> Handle(AutoCompleteRequest var sourceText = await document.GetTextAsync(); var position = sourceText.Lines.GetPosition(new LinePosition(request.Line, request.Column)); + //var options = await document.GetOptionsAsync(); + //options.WithChangedOption(new PerLanguageOption("CompletionOptions", "SnippetsBehavior", SnippetsRule.AlwaysInclude), LanguageNames.CSharp, SnippetsRule.AlwaysInclude); + //options.WithChangedOption() + var semanticModel = await document.GetSemanticModelAsync(); var service = CompletionService.GetService(document); var completionList = await service.GetCompletionsAsync(document, position); + //options: options.WithChangedOption(new PerLanguageOption("CompletionOptions", "SnippetsBehavior", SnippetsRule.AlwaysInclude))); // Add keywords from the completion list. We'll use the recommender service to get symbols // to create snippets from. + + var recommendedSymbols = await Recommender.GetRecommendedSymbolsAtPositionAsync(semanticModel, position, _workspace); + if (completionList != null) { foreach (var item in completionList.Items) { - if (item.Tags.Contains(CompletionTags.Keyword)) + //if (item.Tags.Contains(CompletionTags.Keyword)) { // Note: For keywords, we'll just assume that the completion text is the same // as the display text. var keyword = item.DisplayText; if (keyword.IsValidCompletionFor(wordToComplete)) { + if (item.Properties.ContainsKey("Provider") && item.Properties["Provider"] == "Microsoft.CodeAnalysis.CSharp.Completion.Providers.SymbolCompletionProvider") + { + //var symbolsTask = GetSymbolsAsync.Invoke(null, new object[] { item, document, default(CancellationToken) }) as Task>; + //var symbols = await symbolsTask; + //SymbolFinder. + //foreach (var symbol in symbols.Where(s => s.Name.IsValidCompletionFor(wordToComplete))) + //service.GetDescriptionAsync + { + var symbols = recommendedSymbols.Where(x => x.Name == item.Properties["SymbolName"] && (int)x.Kind == int.Parse(item.Properties["SymbolKind"])).Distinct(); + + if (symbols != null && symbols.Any()) + { + foreach (var symbol in symbols) + { + if (symbol != null) + { + if (request.WantSnippet) + { + foreach (var completion in MakeSnippetedResponses(request, symbol)) + { + completions.Add(completion); + } + } + else + { + completions.Add(MakeAutoCompleteResponse(request, symbol)); + } + } + } + + continue; + } + } + } + var response = new AutoCompleteResponse() { CompletionText = item.DisplayText, DisplayText = item.DisplayText, Snippet = item.DisplayText, - Kind = request.WantKind ? "Keyword" : null + Kind = request.WantKind ? item.Tags.First() : null }; completions.Add(response); @@ -69,23 +112,23 @@ public async Task> Handle(AutoCompleteRequest } } - var model = await document.GetSemanticModelAsync(); - var symbols = await Recommender.GetRecommendedSymbolsAtPositionAsync(model, position, _workspace); - - foreach (var symbol in symbols.Where(s => s.Name.IsValidCompletionFor(wordToComplete))) - { - if (request.WantSnippet) - { - foreach (var completion in MakeSnippetedResponses(request, symbol)) - { - completions.Add(completion); - } - } - else - { - completions.Add(MakeAutoCompleteResponse(request, symbol)); - } - } + //var model = await document.GetSemanticModelAsync(); + //var symbols = await Recommender.GetRecommendedSymbolsAtPositionAsync(model, position, _workspace); + + //foreach (var symbol in symbols.Where(s => s.Name.IsValidCompletionFor(wordToComplete))) + //{ + // if (request.WantSnippet) + // { + // foreach (var completion in MakeSnippetedResponses(request, symbol)) + // { + // completions.Add(completion); + // } + // } + // else + // { + // completions.Add(MakeAutoCompleteResponse(request, symbol)); + // } + //} } return completions diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseV2Service.cs b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseV2Service.cs deleted file mode 100644 index 4c9e385f2f..0000000000 --- a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseV2Service.cs +++ /dev/null @@ -1,226 +0,0 @@ -using System.Collections.Generic; -using System.Composition; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Completion; -using Microsoft.CodeAnalysis.Text; -using OmniSharp.Extensions; -using OmniSharp.Mef; -using OmniSharp.Models.AutoComplete; -using OmniSharp.Options; -using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.Options; -using System.Reflection; -using System.Threading; -using System.Collections.Immutable; -using OmniSharp.Roslyn.CSharp.Services.Documentation; -using Microsoft.CodeAnalysis.Recommendations; - -namespace OmniSharp.Roslyn.CSharp.Services.Intellisense -{ - [OmniSharpHandler(OmniSharpEndpoints.AutoComplete, LanguageNames.CSharp)] - public class IntellisenseService : IRequestHandler> - { - private readonly OmniSharpWorkspace _workspace; - private readonly FormattingOptions _formattingOptions; - - [ImportingConstructor] - public IntellisenseService(OmniSharpWorkspace workspace, FormattingOptions formattingOptions) - { - _workspace = workspace; - _formattingOptions = formattingOptions; - } - - public async Task> Handle(AutoCompleteRequest request) - { - var documents = _workspace.GetDocuments(request.FileName); - var wordToComplete = request.WordToComplete; - var completions = new HashSet(); - - foreach (var document in documents) - { - var sourceText = await document.GetTextAsync(); - var position = sourceText.Lines.GetPosition(new LinePosition(request.Line, request.Column)); - - //var options = await document.GetOptionsAsync(); - //options.WithChangedOption(new PerLanguageOption("CompletionOptions", "SnippetsBehavior", SnippetsRule.AlwaysInclude), LanguageNames.CSharp, SnippetsRule.AlwaysInclude); - //options.WithChangedOption() - var semanticModel = await document.GetSemanticModelAsync(); - var service = CompletionService.GetService(document); - var completionList = await service.GetCompletionsAsync(document, position); - //options: options.WithChangedOption(new PerLanguageOption("CompletionOptions", "SnippetsBehavior", SnippetsRule.AlwaysInclude))); - - // Add keywords from the completion list. We'll use the recommender service to get symbols - // to create snippets from. - - - var recommendedSymbols = await Recommender.GetRecommendedSymbolsAtPositionAsync(semanticModel, position, _workspace); - - if (completionList != null) - { - foreach (var item in completionList.Items) - { - //if (item.Tags.Contains(CompletionTags.Keyword)) - { - // Note: For keywords, we'll just assume that the completion text is the same - // as the display text. - var keyword = item.DisplayText; - if (keyword.IsValidCompletionFor(wordToComplete)) - { - if (item.Properties.ContainsKey("Provider") && item.Properties["Provider"] == "Microsoft.CodeAnalysis.CSharp.Completion.Providers.SymbolCompletionProvider") - { - //var symbolsTask = GetSymbolsAsync.Invoke(null, new object[] { item, document, default(CancellationToken) }) as Task>; - //var symbols = await symbolsTask; - //SymbolFinder. - //foreach (var symbol in symbols.Where(s => s.Name.IsValidCompletionFor(wordToComplete))) - //service.GetDescriptionAsync - { - var symbols = recommendedSymbols.Where(x => x.Name == item.Properties["SymbolName"] && (int)x.Kind == int.Parse(item.Properties["SymbolKind"])).Distinct(); - - if (symbols != null && symbols.Any()) - { - foreach (var symbol in symbols) - { - if (symbol != null) - { - if (request.WantSnippet) - { - foreach (var completion in MakeSnippetedResponses(request, symbol)) - { - completions.Add(completion); - } - } - else - { - completions.Add(MakeAutoCompleteResponse(request, symbol)); - } - } - } - - continue; - } - } - } - - var response = new AutoCompleteResponse() - { - CompletionText = item.DisplayText, - DisplayText = item.DisplayText, - Snippet = item.DisplayText, - Kind = request.WantKind ? item.Tags.First() : null - }; - - completions.Add(response); - } - } - } - } - - //var model = await document.GetSemanticModelAsync(); - //var symbols = await Recommender.GetRecommendedSymbolsAtPositionAsync(model, position, _workspace); - - //foreach (var symbol in symbols.Where(s => s.Name.IsValidCompletionFor(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(wordToComplete)) - .ThenByDescending(c => c.CompletionText.IsValidCompletionStartsWithIgnoreCase(wordToComplete)) - .ThenByDescending(c => c.CompletionText.IsCamelCaseMatch(wordToComplete)) - .ThenByDescending(c => c.CompletionText.IsSubsequenceMatch(wordToComplete)) - .ThenBy(c => c.CompletionText); - } - - private IEnumerable MakeSnippetedResponses(AutoCompleteRequest request, ISymbol symbol) - { - var completions = new List(); - - 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) }; - } - - private AutoCompleteResponse MakeAutoCompleteResponse(AutoCompleteRequest request, ISymbol symbol, bool includeOptionalParams = true) - { - var displayNameGenerator = new SnippetGenerator(); - displayNameGenerator.IncludeMarkers = false; - displayNameGenerator.IncludeOptionalParameters = includeOptionalParams; - - var response = new AutoCompleteResponse(); - response.CompletionText = symbol.Name; - - // TODO: Do something more intelligent here - response.DisplayText = displayNameGenerator.Generate(symbol); - - if (request.WantDocumentationForEveryCompletionResult) - { - response.Description = DocumentationConverter.ConvertDocumentation(symbol.GetDocumentationCommentXml(), _formattingOptions.NewLine); - } - - if (request.WantReturnType) - { - response.ReturnType = ReturnTypeFormatter.GetReturnType(symbol); - } - - if (request.WantKind) - { - response.Kind = symbol.GetKind(); - } - - 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; - } - } -} From 73c78c49dfc552de50d0572494e39e83a6e75c9e Mon Sep 17 00:00:00 2001 From: filipw Date: Sun, 30 Apr 2017 12:43:23 +0200 Subject: [PATCH 04/11] clean up of commented code, comments and logic --- .../Intellisense/IntellisenseService.cs | 116 +++++++----------- 1 file changed, 47 insertions(+), 69 deletions(-) diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs index 65638aadc5..b8eb21eda0 100644 --- a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs +++ b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs @@ -14,6 +14,21 @@ namespace OmniSharp.Roslyn.CSharp.Services.Intellisense { + internal static class CompletionItemExtensions + { + public static IEnumerable GetCompletionSymbols(this CompletionItem completionItem, IEnumerable recommendedSymbols) + { + // for SymbolCompletionProvider, use the logic of extracting information from recommended symbols + if (completionItem.Properties.ContainsKey("Provider") && completionItem.Properties["Provider"] == "Microsoft.CodeAnalysis.CSharp.Completion.Providers.SymbolCompletionProvider") + { + var symbols = recommendedSymbols.Where(x => x.Name == completionItem.Properties["SymbolName"] && (int)x.Kind == int.Parse(completionItem.Properties["SymbolKind"])).Distinct(); + return symbols ?? Enumerable.Empty(); + } + + return Enumerable.Empty(); + } + } + [OmniSharpHandler(OmniSharpEndpoints.AutoComplete, LanguageNames.CSharp)] public class IntellisenseService : IRequestHandler> { @@ -37,98 +52,61 @@ public async Task> Handle(AutoCompleteRequest { var sourceText = await document.GetTextAsync(); var position = sourceText.Lines.GetPosition(new LinePosition(request.Line, request.Column)); - - //var options = await document.GetOptionsAsync(); - //options.WithChangedOption(new PerLanguageOption("CompletionOptions", "SnippetsBehavior", SnippetsRule.AlwaysInclude), LanguageNames.CSharp, SnippetsRule.AlwaysInclude); - //options.WithChangedOption() var semanticModel = await document.GetSemanticModelAsync(); var service = CompletionService.GetService(document); var completionList = await service.GetCompletionsAsync(document, position); - //options: options.WithChangedOption(new PerLanguageOption("CompletionOptions", "SnippetsBehavior", SnippetsRule.AlwaysInclude))); - - // Add keywords from the completion list. We'll use the recommender service to get symbols - // to create snippets from. - - - var recommendedSymbols = await Recommender.GetRecommendedSymbolsAtPositionAsync(semanticModel, position, _workspace); if (completionList != null) { + // get recommened symbols to match them up later with SymbolCompletionProvider + var recommendedSymbols = await Recommender.GetRecommendedSymbolsAtPositionAsync(semanticModel, position, _workspace); + foreach (var item in completionList.Items) { - //if (item.Tags.Contains(CompletionTags.Keyword)) + var completionText = item.DisplayText; + if (completionText.IsValidCompletionFor(wordToComplete)) { - // Note: For keywords, we'll just assume that the completion text is the same - // as the display text. - var keyword = item.DisplayText; - if (keyword.IsValidCompletionFor(wordToComplete)) + var symbols = item.GetCompletionSymbols(recommendedSymbols); + if (symbols.Any()) { - if (item.Properties.ContainsKey("Provider") && item.Properties["Provider"] == "Microsoft.CodeAnalysis.CSharp.Completion.Providers.SymbolCompletionProvider") + foreach (var symbol in symbols) { - //var symbolsTask = GetSymbolsAsync.Invoke(null, new object[] { item, document, default(CancellationToken) }) as Task>; - //var symbols = await symbolsTask; - //SymbolFinder. - //foreach (var symbol in symbols.Where(s => s.Name.IsValidCompletionFor(wordToComplete))) - //service.GetDescriptionAsync + if (symbol != null) { - var symbols = recommendedSymbols.Where(x => x.Name == item.Properties["SymbolName"] && (int)x.Kind == int.Parse(item.Properties["SymbolKind"])).Distinct(); - - if (symbols != null && symbols.Any()) + if (request.WantSnippet) { - foreach (var symbol in symbols) + foreach (var completion in MakeSnippetedResponses(request, symbol)) { - if (symbol != null) - { - if (request.WantSnippet) - { - foreach (var completion in MakeSnippetedResponses(request, symbol)) - { - completions.Add(completion); - } - } - else - { - completions.Add(MakeAutoCompleteResponse(request, symbol)); - } - } + completions.Add(completion); } - - continue; + } + else + { + completions.Add(MakeAutoCompleteResponse(request, symbol)); } } } - var response = new AutoCompleteResponse() - { - CompletionText = item.DisplayText, - DisplayText = item.DisplayText, - Snippet = item.DisplayText, - Kind = request.WantKind ? item.Tags.First() : null - }; - - completions.Add(response); + // if we had any symbols from the completion, we can continue, otherwise it means + // the completion didn't have an associated symbol so we'll add it manually + continue; } + + // for other completions, i.e. keywords, create a simple AutoCompleteResponse + // we'll just assume that the completion text is the same + // as the display text. + var response = new AutoCompleteResponse() + { + CompletionText = item.DisplayText, + DisplayText = item.DisplayText, + Snippet = item.DisplayText, + Kind = request.WantKind ? item.Tags.First() : null + }; + + completions.Add(response); } } } - - //var model = await document.GetSemanticModelAsync(); - //var symbols = await Recommender.GetRecommendedSymbolsAtPositionAsync(model, position, _workspace); - - //foreach (var symbol in symbols.Where(s => s.Name.IsValidCompletionFor(wordToComplete))) - //{ - // if (request.WantSnippet) - // { - // foreach (var completion in MakeSnippetedResponses(request, symbol)) - // { - // completions.Add(completion); - // } - // } - // else - // { - // completions.Add(MakeAutoCompleteResponse(request, symbol)); - // } - //} } return completions From e82f2e8252cef89bc3a3b1312b903dce50ca0308 Mon Sep 17 00:00:00 2001 From: filipw Date: Sun, 30 Apr 2017 13:00:01 +0200 Subject: [PATCH 05/11] extracted CompletionItemExtensions --- .../Intellisense/CompletionItemExtensions.cs | 37 +++++++++++++++++++ .../Intellisense/IntellisenseService.cs | 37 ++++++------------- 2 files changed, 48 insertions(+), 26 deletions(-) create mode 100644 src/OmniSharp.Roslyn.CSharp/Services/Intellisense/CompletionItemExtensions.cs diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/CompletionItemExtensions.cs b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/CompletionItemExtensions.cs new file mode 100644 index 0000000000..17db317ff1 --- /dev/null +++ b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/CompletionItemExtensions.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Completion; + +namespace OmniSharp.Roslyn.CSharp.Services.Intellisense +{ + internal static class CompletionItemExtensions + { + public static async Task> GetCompletionSymbols(this CompletionItem completionItem, IEnumerable recommendedSymbols, Document document) + { + // for SymbolCompletionProvider, use the logic of extracting information from recommended symbols + if (completionItem.Properties.ContainsKey("Provider") && completionItem.Properties["Provider"] == "Microsoft.CodeAnalysis.CSharp.Completion.Providers.SymbolCompletionProvider") + { + var symbols = recommendedSymbols.Where(x => x.Name == completionItem.Properties["SymbolName"] && (int)x.Kind == int.Parse(completionItem.Properties["SymbolKind"])).Distinct(); + return symbols ?? Enumerable.Empty(); + } + + // if the completion provider encoded symbols into Properties, we can return them + if (completionItem.Properties.ContainsKey("Symbols")) + { + var symbolCompletionItemType = typeof(CompletionItem).GetTypeInfo().Assembly.GetType("Microsoft.CodeAnalysis.Completion.Providers.SymbolCompletionItem"); + var getSymbolsAsync = symbolCompletionItemType.GetMethod("GetSymbolsAsync", BindingFlags.Public | BindingFlags.Static); + var decodedSymbolsTask = getSymbolsAsync.Invoke(null, new object[] { completionItem, document, default(CancellationToken) }) as Task>; + if (decodedSymbolsTask != null) + { + return await decodedSymbolsTask; + } + } + + return Enumerable.Empty(); + } + } +} diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs index b8eb21eda0..c26e0f22d0 100644 --- a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs +++ b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs @@ -14,21 +14,6 @@ namespace OmniSharp.Roslyn.CSharp.Services.Intellisense { - internal static class CompletionItemExtensions - { - public static IEnumerable GetCompletionSymbols(this CompletionItem completionItem, IEnumerable recommendedSymbols) - { - // for SymbolCompletionProvider, use the logic of extracting information from recommended symbols - if (completionItem.Properties.ContainsKey("Provider") && completionItem.Properties["Provider"] == "Microsoft.CodeAnalysis.CSharp.Completion.Providers.SymbolCompletionProvider") - { - var symbols = recommendedSymbols.Where(x => x.Name == completionItem.Properties["SymbolName"] && (int)x.Kind == int.Parse(completionItem.Properties["SymbolKind"])).Distinct(); - return symbols ?? Enumerable.Empty(); - } - - return Enumerable.Empty(); - } - } - [OmniSharpHandler(OmniSharpEndpoints.AutoComplete, LanguageNames.CSharp)] public class IntellisenseService : IRequestHandler> { @@ -66,7 +51,7 @@ public async Task> Handle(AutoCompleteRequest var completionText = item.DisplayText; if (completionText.IsValidCompletionFor(wordToComplete)) { - var symbols = item.GetCompletionSymbols(recommendedSymbols); + var symbols = await item.GetCompletionSymbols(recommendedSymbols, document); if (symbols.Any()) { foreach (var symbol in symbols) @@ -75,14 +60,14 @@ public async Task> Handle(AutoCompleteRequest { if (request.WantSnippet) { - foreach (var completion in MakeSnippetedResponses(request, symbol)) + foreach (var completion in MakeSnippetedResponses(request, symbol, item.DisplayText)) { completions.Add(completion); } } else { - completions.Add(MakeAutoCompleteResponse(request, symbol)); + completions.Add(MakeAutoCompleteResponse(request, symbol, item.DisplayText)); } } } @@ -117,7 +102,7 @@ public async Task> Handle(AutoCompleteRequest .ThenBy(c => c.CompletionText); } - private IEnumerable MakeSnippetedResponses(AutoCompleteRequest request, ISymbol symbol) + private IEnumerable MakeSnippetedResponses(AutoCompleteRequest request, ISymbol symbol, string displayName) { var completions = new List(); @@ -126,10 +111,10 @@ private IEnumerable MakeSnippetedResponses(AutoCompleteReq { if (methodSymbol.Parameters.Any(p => p.IsOptional)) { - completions.Add(MakeAutoCompleteResponse(request, symbol, false)); + completions.Add(MakeAutoCompleteResponse(request, symbol, displayName, false)); } - completions.Add(MakeAutoCompleteResponse(request, symbol)); + completions.Add(MakeAutoCompleteResponse(request, symbol, displayName)); return completions; } @@ -137,30 +122,30 @@ private IEnumerable MakeSnippetedResponses(AutoCompleteReq var typeSymbol = symbol as INamedTypeSymbol; if (typeSymbol != null) { - completions.Add(MakeAutoCompleteResponse(request, symbol)); + completions.Add(MakeAutoCompleteResponse(request, symbol, displayName)); if (typeSymbol.TypeKind != TypeKind.Enum) { foreach (var ctor in typeSymbol.InstanceConstructors) { - completions.Add(MakeAutoCompleteResponse(request, ctor)); + completions.Add(MakeAutoCompleteResponse(request, ctor, displayName)); } } return completions; } - return new[] { MakeAutoCompleteResponse(request, symbol) }; + return new[] { MakeAutoCompleteResponse(request, symbol, displayName) }; } - private AutoCompleteResponse MakeAutoCompleteResponse(AutoCompleteRequest request, ISymbol symbol, bool includeOptionalParams = true) + private AutoCompleteResponse MakeAutoCompleteResponse(AutoCompleteRequest request, ISymbol symbol, string displayName, bool includeOptionalParams = true) { var displayNameGenerator = new SnippetGenerator(); displayNameGenerator.IncludeMarkers = false; displayNameGenerator.IncludeOptionalParameters = includeOptionalParams; var response = new AutoCompleteResponse(); - response.CompletionText = symbol.Name; + response.CompletionText = displayName; // TODO: Do something more intelligent here response.DisplayText = displayNameGenerator.Generate(symbol); From 5a34a46298d86231343b660872b2b3dd574eec81 Mon Sep 17 00:00:00 2001 From: filipw Date: Sun, 30 Apr 2017 13:10:21 +0200 Subject: [PATCH 06/11] cache GetSymbolsAsync --- .../Intellisense/CompletionItemExtensions.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/CompletionItemExtensions.cs b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/CompletionItemExtensions.cs index 17db317ff1..13c38c3b77 100644 --- a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/CompletionItemExtensions.cs +++ b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/CompletionItemExtensions.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; -using System.Text; +using System.Reflection; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Completion; @@ -10,6 +12,14 @@ namespace OmniSharp.Roslyn.CSharp.Services.Intellisense { internal static class CompletionItemExtensions { + private static MethodInfo _getSymbolsAsync; + + static CompletionItemExtensions() + { + var symbolCompletionItemType = typeof(CompletionItem).GetTypeInfo().Assembly.GetType("Microsoft.CodeAnalysis.Completion.Providers.SymbolCompletionItem"); + _getSymbolsAsync = symbolCompletionItemType.GetMethod("GetSymbolsAsync", BindingFlags.Public | BindingFlags.Static); + } + public static async Task> GetCompletionSymbols(this CompletionItem completionItem, IEnumerable recommendedSymbols, Document document) { // for SymbolCompletionProvider, use the logic of extracting information from recommended symbols @@ -22,9 +32,9 @@ public static async Task> GetCompletionSymbols(this Complet // if the completion provider encoded symbols into Properties, we can return them if (completionItem.Properties.ContainsKey("Symbols")) { - var symbolCompletionItemType = typeof(CompletionItem).GetTypeInfo().Assembly.GetType("Microsoft.CodeAnalysis.Completion.Providers.SymbolCompletionItem"); - var getSymbolsAsync = symbolCompletionItemType.GetMethod("GetSymbolsAsync", BindingFlags.Public | BindingFlags.Static); - var decodedSymbolsTask = getSymbolsAsync.Invoke(null, new object[] { completionItem, document, default(CancellationToken) }) as Task>; + // the API to decode symbols is not public at the moment + // http://source.roslyn.io/#Microsoft.CodeAnalysis.Features/Completion/Providers/SymbolCompletionItem.cs,93 + var decodedSymbolsTask = _getSymbolsAsync.Invoke(null, new object[] { completionItem, document, default(CancellationToken) }) as Task>; if (decodedSymbolsTask != null) { return await decodedSymbolsTask; From d8e066a6456e75d7111b1873a97cca629c301081 Mon Sep 17 00:00:00 2001 From: filipw Date: Sun, 30 Apr 2017 20:36:51 +0200 Subject: [PATCH 07/11] use OmniSharp reflection extensions use async suffix on GetCompletionSymbolsAsync move semantic model --- .../Services/Intellisense/CompletionItemExtensions.cs | 5 +++-- .../Services/Intellisense/IntellisenseService.cs | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/CompletionItemExtensions.cs b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/CompletionItemExtensions.cs index 13c38c3b77..b3d552d95a 100644 --- a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/CompletionItemExtensions.cs +++ b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/CompletionItemExtensions.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Completion; +using OmniSharp.Utilities; namespace OmniSharp.Roslyn.CSharp.Services.Intellisense { @@ -20,7 +21,7 @@ static CompletionItemExtensions() _getSymbolsAsync = symbolCompletionItemType.GetMethod("GetSymbolsAsync", BindingFlags.Public | BindingFlags.Static); } - public static async Task> GetCompletionSymbols(this CompletionItem completionItem, IEnumerable recommendedSymbols, Document document) + public static async Task> GetCompletionSymbolsAsync(this CompletionItem completionItem, IEnumerable recommendedSymbols, Document document) { // for SymbolCompletionProvider, use the logic of extracting information from recommended symbols if (completionItem.Properties.ContainsKey("Provider") && completionItem.Properties["Provider"] == "Microsoft.CodeAnalysis.CSharp.Completion.Providers.SymbolCompletionProvider") @@ -34,7 +35,7 @@ public static async Task> GetCompletionSymbols(this Complet { // the API to decode symbols is not public at the moment // http://source.roslyn.io/#Microsoft.CodeAnalysis.Features/Completion/Providers/SymbolCompletionItem.cs,93 - var decodedSymbolsTask = _getSymbolsAsync.Invoke(null, new object[] { completionItem, document, default(CancellationToken) }) as Task>; + var decodedSymbolsTask = _getSymbolsAsync.InvokeStatic>>(new object[] { completionItem, document, default(CancellationToken) }); if (decodedSymbolsTask != null) { return await decodedSymbolsTask; diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs index c26e0f22d0..9f2e4d33ca 100644 --- a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs +++ b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs @@ -37,13 +37,13 @@ public async Task> Handle(AutoCompleteRequest { var sourceText = await document.GetTextAsync(); var position = sourceText.Lines.GetPosition(new LinePosition(request.Line, request.Column)); - var semanticModel = await document.GetSemanticModelAsync(); var service = CompletionService.GetService(document); var completionList = await service.GetCompletionsAsync(document, position); if (completionList != null) { // get recommened symbols to match them up later with SymbolCompletionProvider + var semanticModel = await document.GetSemanticModelAsync(); var recommendedSymbols = await Recommender.GetRecommendedSymbolsAtPositionAsync(semanticModel, position, _workspace); foreach (var item in completionList.Items) @@ -51,7 +51,7 @@ public async Task> Handle(AutoCompleteRequest var completionText = item.DisplayText; if (completionText.IsValidCompletionFor(wordToComplete)) { - var symbols = await item.GetCompletionSymbols(recommendedSymbols, document); + var symbols = await item.GetCompletionSymbolsAsync(recommendedSymbols, document); if (symbols.Any()) { foreach (var symbol in symbols) From ab55defe41f61a20b141cd2cbfd90d880bcf95dc Mon Sep 17 00:00:00 2001 From: filipw Date: Sun, 30 Apr 2017 22:51:10 +0200 Subject: [PATCH 08/11] added attribute completion and object initializer completion tests --- .../IntellisenseFacts.cs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tests/OmniSharp.Roslyn.CSharp.Tests/IntellisenseFacts.cs b/tests/OmniSharp.Roslyn.CSharp.Tests/IntellisenseFacts.cs index 0f10597f21..edc5d09947 100644 --- a/tests/OmniSharp.Roslyn.CSharp.Tests/IntellisenseFacts.cs +++ b/tests/OmniSharp.Roslyn.CSharp.Tests/IntellisenseFacts.cs @@ -202,6 +202,47 @@ var x$$ ContainsCompletions(completions.Select(c => c.CompletionText), Array.Empty()); } + [Theory] + [InlineData("dummy.cs")] + [InlineData("dummy.csx")] + public async Task Returns_attribute_without_attribute_suffix(string filename) + { + const string source = + @"using System; + + public class BarAttribute : Attribute {} + + [B$$ + public class Foo {}"; + + var completions = await FindCompletionsAsync(filename, source); + ContainsCompletions(completions.Select(c => c.CompletionText).Take(1), "Bar"); + } + + [Theory] + [InlineData("dummy.cs")] + [InlineData("dummy.csx")] + public async Task Returns_members_in_object_initializer_context(string filename) + { + const string source = + @"public class MyClass1 { + public string Foo {get; set;} + } + + public class MyClass2 { + + public MyClass2() + { + var c = new MyClass1 { + F$$ + } + } + "; + + var completions = await FindCompletionsAsync(filename, source); + ContainsCompletions(completions.Select(c => c.CompletionText), "Foo"); + } + private void ContainsCompletions(IEnumerable completions, params string[] expected) { if (!completions.SequenceEqual(expected)) From b1790676ae954d94e6c88bc4260fdcb3a7739b77 Mon Sep 17 00:00:00 2001 From: filipw Date: Sun, 30 Apr 2017 23:10:29 +0200 Subject: [PATCH 09/11] added more tests to IntellisenseFacts --- .../IntellisenseFacts.cs | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/tests/OmniSharp.Roslyn.CSharp.Tests/IntellisenseFacts.cs b/tests/OmniSharp.Roslyn.CSharp.Tests/IntellisenseFacts.cs index edc5d09947..f224085fbe 100644 --- a/tests/OmniSharp.Roslyn.CSharp.Tests/IntellisenseFacts.cs +++ b/tests/OmniSharp.Roslyn.CSharp.Tests/IntellisenseFacts.cs @@ -243,6 +243,69 @@ public MyClass2() ContainsCompletions(completions.Select(c => c.CompletionText), "Foo"); } + [Theory] + [InlineData("dummy.cs")] + [InlineData("dummy.csx")] + public async Task Returns_parameter_name_inside_a_method(string filename) + { + const string source = + @"public class MyClass1 { + public void SayHi(string text) {} + } + + public class MyClass2 { + + public MyClass2() + { + var c = new MyClass1(); + c.SayHi(te$$ + } + } + "; + + var completions = await FindCompletionsAsync(filename, source); + ContainsCompletions(completions.Select(c => c.CompletionText).Take(1), "text:"); + } + + [Theory] + [InlineData("dummy.cs")] + [InlineData("dummy.csx")] + public async Task Returns_override_signatures(string filename) + { + const string source = + @"class Foo + { + public virtual void Test(string text) {} + public virtual void Test(string text, string moreText) {} + } + + class FooChild : Foo + { + override $$ + } + "; + + var completions = await FindCompletionsAsync(filename, source); + ContainsCompletions(completions.Select(c => c.CompletionText), "Equals(object obj)", "GetHashCode()", "Test(string text)", "Test(string text, string moreText)", "ToString()"); + } + + [Theory] + [InlineData("dummy.cs")] + [InlineData("dummy.csx")] + public async Task Returns_cref_completion(string filename) + { + const string source = + @" /// + /// A comment. for more details + /// + public class MyClass1 { + } + "; + + var completions = await FindCompletionsAsync(filename, source); + ContainsCompletions(completions.Select(c => c.CompletionText).Take(1), "MyClass1"); + } + private void ContainsCompletions(IEnumerable completions, params string[] expected) { if (!completions.SequenceEqual(expected)) From 5643a01ebbcffffbbf0d307e889c83c5268c933f Mon Sep 17 00:00:00 2001 From: filipw Date: Tue, 2 May 2017 08:36:54 +0200 Subject: [PATCH 10/11] better completion sorting, and consistent across Windows and Nix --- .../Services/Intellisense/IntellisenseService.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs index 9f2e4d33ca..6383d200c3 100644 --- a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs +++ b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/IntellisenseService.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Composition; using System.Linq; @@ -99,7 +100,8 @@ public async Task> Handle(AutoCompleteRequest .ThenByDescending(c => c.CompletionText.IsValidCompletionStartsWithIgnoreCase(wordToComplete)) .ThenByDescending(c => c.CompletionText.IsCamelCaseMatch(wordToComplete)) .ThenByDescending(c => c.CompletionText.IsSubsequenceMatch(wordToComplete)) - .ThenBy(c => c.CompletionText); + .ThenBy(c => c.DisplayText, StringComparer.OrdinalIgnoreCase) + .ThenBy(c => c.CompletionText, StringComparer.OrdinalIgnoreCase); } private IEnumerable MakeSnippetedResponses(AutoCompleteRequest request, ISymbol symbol, string displayName) From 62fe53a146e75b43a9f7d14f7daf557331dfe091 Mon Sep 17 00:00:00 2001 From: filipw Date: Tue, 2 May 2017 17:36:49 +0200 Subject: [PATCH 11/11] no need to check for null after Where --- .../Services/Intellisense/CompletionItemExtensions.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/CompletionItemExtensions.cs b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/CompletionItemExtensions.cs index b3d552d95a..703c3ff72a 100644 --- a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/CompletionItemExtensions.cs +++ b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/CompletionItemExtensions.cs @@ -26,8 +26,7 @@ public static async Task> GetCompletionSymbolsAsync(this Co // for SymbolCompletionProvider, use the logic of extracting information from recommended symbols if (completionItem.Properties.ContainsKey("Provider") && completionItem.Properties["Provider"] == "Microsoft.CodeAnalysis.CSharp.Completion.Providers.SymbolCompletionProvider") { - var symbols = recommendedSymbols.Where(x => x.Name == completionItem.Properties["SymbolName"] && (int)x.Kind == int.Parse(completionItem.Properties["SymbolKind"])).Distinct(); - return symbols ?? Enumerable.Empty(); + return recommendedSymbols.Where(x => x.Name == completionItem.Properties["SymbolName"] && (int)x.Kind == int.Parse(completionItem.Properties["SymbolKind"])).Distinct(); } // if the completion provider encoded symbols into Properties, we can return them