Merge pull request #9194 from DustinCampbell/completion-cleanup

Clean up completion to return ImmutableArray<T> rather than IReadOnlyList<T>
This commit is contained in:
Dustin Campbell 2023-08-30 10:05:57 -07:00 коммит произвёл GitHub
Родитель f3fac0332f 7c378c8b75
Коммит 548eefdfed
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
36 изменённых файлов: 499 добавлений и 437 удалений

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license. See License.txt in the project root for license information. // Licensed under the MIT license. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic; using System.Collections.Immutable;
using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.Language.Syntax;
using Microsoft.AspNetCore.Razor.LanguageServer.Extensions; using Microsoft.AspNetCore.Razor.LanguageServer.Extensions;
@ -39,9 +39,9 @@ internal class DirectiveAttributeTransitionCompletionItemProvider : DirectiveAtt
} }
} }
private static readonly IReadOnlyList<RazorCompletionItem> s_completions = new[] { TransitionCompletionItem }; private static readonly ImmutableArray<RazorCompletionItem> s_completions = ImmutableArray.Create(TransitionCompletionItem);
public override IReadOnlyList<RazorCompletionItem> GetCompletionItems(RazorCompletionContext context) public override ImmutableArray<RazorCompletionItem> GetCompletionItems(RazorCompletionContext context)
{ {
if (context is null) if (context is null)
{ {
@ -51,13 +51,13 @@ internal class DirectiveAttributeTransitionCompletionItemProvider : DirectiveAtt
if (!FileKinds.IsComponent(context.SyntaxTree.Options.FileKind)) if (!FileKinds.IsComponent(context.SyntaxTree.Options.FileKind))
{ {
// Directive attributes are only supported in components // Directive attributes are only supported in components
return Array.Empty<RazorCompletionItem>(); return ImmutableArray<RazorCompletionItem>.Empty;
} }
var owner = context.Owner; var owner = context.Owner;
if (owner is null) if (owner is null)
{ {
return Array.Empty<RazorCompletionItem>(); return ImmutableArray<RazorCompletionItem>.Empty;
} }
var attribute = owner.Parent; var attribute = owner.Parent;
@ -69,19 +69,19 @@ internal class DirectiveAttributeTransitionCompletionItemProvider : DirectiveAtt
if (!TryGetAttributeInfo(owner, out var prefixLocation, out var attributeName, out var attributeNameLocation, out _, out _)) if (!TryGetAttributeInfo(owner, out var prefixLocation, out var attributeName, out var attributeNameLocation, out _, out _))
{ {
return Array.Empty<RazorCompletionItem>(); return ImmutableArray<RazorCompletionItem>.Empty;
} }
if (attributeNameLocation.IntersectsWith(context.AbsoluteIndex) && attributeName.StartsWith("@", StringComparison.Ordinal)) if (attributeNameLocation.IntersectsWith(context.AbsoluteIndex) && attributeName.StartsWith("@", StringComparison.Ordinal))
{ {
// The transition is already provided for the attribute name // The transition is already provided for the attribute name
return Array.Empty<RazorCompletionItem>(); return ImmutableArray<RazorCompletionItem>.Empty;
} }
if (!IsValidCompletionPoint(context.AbsoluteIndex, prefixLocation, attributeNameLocation)) if (!IsValidCompletionPoint(context.AbsoluteIndex, prefixLocation, attributeNameLocation))
{ {
// Not operating in the attribute name area // Not operating in the attribute name area
return Array.Empty<RazorCompletionItem>(); return ImmutableArray<RazorCompletionItem>.Empty;
} }
// This represents a tag when there's no attribute content <InputText | />. // This represents a tag when there's no attribute content <InputText | />.

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license. See License.txt in the project root for license information. // Licensed under the MIT license. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic; using System.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Legacy; using Microsoft.AspNetCore.Razor.Language.Legacy;
using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts; using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts;
using Microsoft.AspNetCore.Razor.LanguageServer.Extensions; using Microsoft.AspNetCore.Razor.LanguageServer.Extensions;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.CodeAnalysis.Razor.Completion; using Microsoft.CodeAnalysis.Razor.Completion;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.LanguageServer.Protocol;
@ -23,7 +24,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion;
// for this legacy version. // for this legacy version.
internal class LegacyRazorCompletionEndpoint : IVSCompletionEndpoint internal class LegacyRazorCompletionEndpoint : IVSCompletionEndpoint
{ {
private readonly RazorCompletionFactsService _completionFactsService; private readonly IRazorCompletionFactsService _completionFactsService;
private readonly CompletionListCache _completionListCache; private readonly CompletionListCache _completionListCache;
private static readonly Command s_retriggerCompletionCommand = new() private static readonly Command s_retriggerCompletionCommand = new()
{ {
@ -34,22 +35,10 @@ internal class LegacyRazorCompletionEndpoint : IVSCompletionEndpoint
public bool MutatesSolutionState => false; public bool MutatesSolutionState => false;
public LegacyRazorCompletionEndpoint( public LegacyRazorCompletionEndpoint(IRazorCompletionFactsService completionFactsService, CompletionListCache completionListCache)
RazorCompletionFactsService completionFactsService,
CompletionListCache completionListCache)
{ {
if (completionFactsService is null) _completionFactsService = completionFactsService ?? throw new ArgumentNullException(nameof(completionFactsService));
{ _completionListCache = completionListCache ?? throw new ArgumentNullException(nameof(completionListCache));
throw new ArgumentNullException(nameof(completionFactsService));
}
if (completionListCache is null)
{
throw new ArgumentNullException(nameof(completionListCache));
}
_completionFactsService = completionFactsService;
_completionListCache = completionListCache;
} }
public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, VSInternalClientCapabilities clientCapabilities) public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, VSInternalClientCapabilities clientCapabilities)
@ -107,7 +96,7 @@ internal class LegacyRazorCompletionEndpoint : IVSCompletionEndpoint
var razorCompletionItems = _completionFactsService.GetCompletionItems(completionContext); var razorCompletionItems = _completionFactsService.GetCompletionItems(completionContext);
requestContext.Logger.LogTrace("Resolved {razorCompletionItemsCount} completion items.", razorCompletionItems.Count); requestContext.Logger.LogTrace("Resolved {razorCompletionItemsCount} completion items.", razorCompletionItems.Length);
var completionList = CreateLSPCompletionList(razorCompletionItems); var completionList = CreateLSPCompletionList(razorCompletionItems);
var completionCapability = _clientCapabilities?.TextDocument?.Completion as VSInternalCompletionSetting; var completionCapability = _clientCapabilities?.TextDocument?.Completion as VSInternalCompletionSetting;
@ -140,31 +129,33 @@ internal class LegacyRazorCompletionEndpoint : IVSCompletionEndpoint
} }
// Internal for testing // Internal for testing
internal VSInternalCompletionList CreateLSPCompletionList(IReadOnlyList<RazorCompletionItem> razorCompletionItems) => CreateLSPCompletionList(razorCompletionItems, _clientCapabilities!); internal VSInternalCompletionList CreateLSPCompletionList(ImmutableArray<RazorCompletionItem> razorCompletionItems)
=> CreateLSPCompletionList(razorCompletionItems, _clientCapabilities!);
// Internal for benchmarking and testing // Internal for benchmarking and testing
internal static VSInternalCompletionList CreateLSPCompletionList( internal static VSInternalCompletionList CreateLSPCompletionList(
IReadOnlyList<RazorCompletionItem> razorCompletionItems, ImmutableArray<RazorCompletionItem> razorCompletionItems,
VSInternalClientCapabilities clientCapabilities) VSInternalClientCapabilities clientCapabilities)
{ {
var completionItems = new List<CompletionItem>(); using var items = new PooledArrayBuilder<CompletionItem>();
foreach (var razorCompletionItem in razorCompletionItems) foreach (var razorCompletionItem in razorCompletionItems)
{ {
if (TryConvert(razorCompletionItem, clientCapabilities, out var completionItem)) if (TryConvert(razorCompletionItem, clientCapabilities, out var completionItem))
{ {
completionItems.Add(completionItem); items.Add(completionItem);
} }
} }
var completionList = new VSInternalCompletionList() var completionList = new VSInternalCompletionList()
{ {
Items = completionItems.ToArray(), Items = items.ToArray(),
IsIncomplete = false, IsIncomplete = false,
}; };
var completionCapability = clientCapabilities?.TextDocument?.Completion as VSInternalCompletionSetting; var completionCapability = clientCapabilities?.TextDocument?.Completion as VSInternalCompletionSetting;
var optimizedCompletionList = CompletionListOptimizer.Optimize(completionList, completionCapability);
return optimizedCompletionList; return CompletionListOptimizer.Optimize(completionList, completionCapability);
} }
// Internal for testing // Internal for testing

Просмотреть файл

@ -12,6 +12,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Legacy; using Microsoft.AspNetCore.Razor.Language.Legacy;
using Microsoft.AspNetCore.Razor.LanguageServer.Extensions; using Microsoft.AspNetCore.Razor.LanguageServer.Extensions;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.CodeAnalysis.Razor.Completion; using Microsoft.CodeAnalysis.Razor.Completion;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.LanguageServer.Protocol;
@ -20,7 +21,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion;
internal class RazorCompletionListProvider internal class RazorCompletionListProvider
{ {
private readonly RazorCompletionFactsService _completionFactsService; private readonly IRazorCompletionFactsService _completionFactsService;
private readonly CompletionListCache _completionListCache; private readonly CompletionListCache _completionListCache;
private readonly ILogger<RazorCompletionListProvider> _logger; private readonly ILogger<RazorCompletionListProvider> _logger;
private static readonly Command s_retriggerCompletionCommand = new() private static readonly Command s_retriggerCompletionCommand = new()
@ -30,7 +31,7 @@ internal class RazorCompletionListProvider
}; };
public RazorCompletionListProvider( public RazorCompletionListProvider(
RazorCompletionFactsService completionFactsService, IRazorCompletionFactsService completionFactsService,
CompletionListCache completionListCache, CompletionListCache completionListCache,
ILoggerFactory loggerFactory) ILoggerFactory loggerFactory)
{ {
@ -63,6 +64,7 @@ internal class RazorCompletionListProvider
CompletionTriggerKind.TriggerCharacter => CompletionReason.Typing, CompletionTriggerKind.TriggerCharacter => CompletionReason.Typing,
_ => CompletionReason.Typing, _ => CompletionReason.Typing,
}; };
var completionOptions = new RazorCompletionOptions(SnippetsSupported: true); var completionOptions = new RazorCompletionOptions(SnippetsSupported: true);
var syntaxTree = await documentContext.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var syntaxTree = await documentContext.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var tagHelperContext = await documentContext.GetTagHelperContextAsync(cancellationToken).ConfigureAwait(false); var tagHelperContext = await documentContext.GetTagHelperContextAsync(cancellationToken).ConfigureAwait(false);
@ -79,7 +81,7 @@ internal class RazorCompletionListProvider
var razorCompletionItems = _completionFactsService.GetCompletionItems(razorCompletionContext); var razorCompletionItems = _completionFactsService.GetCompletionItems(razorCompletionContext);
_logger.LogTrace("Resolved {razorCompletionItemsCount} completion items.", razorCompletionItems.Count); _logger.LogTrace("Resolved {razorCompletionItemsCount} completion items.", razorCompletionItems.Length);
var completionList = CreateLSPCompletionList(razorCompletionItems, clientCapabilities); var completionList = CreateLSPCompletionList(razorCompletionItems, clientCapabilities);
@ -94,27 +96,28 @@ internal class RazorCompletionListProvider
// Internal for benchmarking and testing // Internal for benchmarking and testing
internal static VSInternalCompletionList CreateLSPCompletionList( internal static VSInternalCompletionList CreateLSPCompletionList(
IReadOnlyList<RazorCompletionItem> razorCompletionItems, ImmutableArray<RazorCompletionItem> razorCompletionItems,
VSInternalClientCapabilities clientCapabilities) VSInternalClientCapabilities clientCapabilities)
{ {
var completionItems = new List<CompletionItem>(); using var items = new PooledArrayBuilder<CompletionItem>();
foreach (var razorCompletionItem in razorCompletionItems) foreach (var razorCompletionItem in razorCompletionItems)
{ {
if (TryConvert(razorCompletionItem, clientCapabilities, out var completionItem)) if (TryConvert(razorCompletionItem, clientCapabilities, out var completionItem))
{ {
completionItems.Add(completionItem); items.Add(completionItem);
} }
} }
var completionList = new VSInternalCompletionList() var completionList = new VSInternalCompletionList()
{ {
Items = completionItems.ToArray(), Items = items.ToArray(),
IsIncomplete = false, IsIncomplete = false,
}; };
var completionCapability = clientCapabilities.TextDocument?.Completion as VSInternalCompletionSetting; var completionCapability = clientCapabilities.TextDocument?.Completion as VSInternalCompletionSetting;
var optimizedCompletionList = CompletionListOptimizer.Optimize(completionList, completionCapability);
return optimizedCompletionList; return CompletionListOptimizer.Optimize(completionList, completionCapability);
} }
// Internal for testing // Internal for testing

Просмотреть файл

@ -3,11 +3,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.Language.Syntax;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.CodeAnalysis.Razor.Completion; using Microsoft.CodeAnalysis.Razor.Completion;
using Microsoft.CodeAnalysis.Razor.Tooltip; using Microsoft.CodeAnalysis.Razor.Tooltip;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -15,7 +17,7 @@ using Microsoft.VisualStudio.Editor.Razor;
namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion; namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion;
internal class TagHelperCompletionProvider : RazorCompletionItemProvider internal class TagHelperCompletionProvider : IRazorCompletionItemProvider
{ {
// Internal for testing // Internal for testing
internal static readonly IReadOnlyList<RazorCommitCharacter> MinimizedAttributeCommitCharacters = RazorCommitCharacter.FromArray(new[] { "=", " " }); internal static readonly IReadOnlyList<RazorCommitCharacter> MinimizedAttributeCommitCharacters = RazorCommitCharacter.FromArray(new[] { "=", " " });
@ -41,7 +43,7 @@ internal class TagHelperCompletionProvider : RazorCompletionItemProvider
_optionsMonitor = optionsMonitor ?? throw new ArgumentNullException(nameof(optionsMonitor)); _optionsMonitor = optionsMonitor ?? throw new ArgumentNullException(nameof(optionsMonitor));
} }
public override IReadOnlyList<RazorCompletionItem> GetCompletionItems(RazorCompletionContext context) public ImmutableArray<RazorCompletionItem> GetCompletionItems(RazorCompletionContext context)
{ {
if (context is null) if (context is null)
{ {
@ -52,7 +54,7 @@ internal class TagHelperCompletionProvider : RazorCompletionItemProvider
if (owner is null) if (owner is null)
{ {
Debug.Fail("Owner should never be null."); Debug.Fail("Owner should never be null.");
return Array.Empty<RazorCompletionItem>(); return ImmutableArray<RazorCompletionItem>.Empty;
} }
var parent = owner.Parent; var parent = owner.Parent;
@ -102,13 +104,13 @@ internal class TagHelperCompletionProvider : RazorCompletionItemProvider
// //
// Will be interpreted as having an `@code` attribute name due to multi-line attributes being a thing. Ultimately this is mostly a // Will be interpreted as having an `@code` attribute name due to multi-line attributes being a thing. Ultimately this is mostly a
// heuristic that we have to apply in order to workaround limitations of the Razor compiler. // heuristic that we have to apply in order to workaround limitations of the Razor compiler.
return Array.Empty<RazorCompletionItem>(); return ImmutableArray<RazorCompletionItem>.Empty;
} }
var stringifiedAttributes = _tagHelperFactsService.StringifyAttributes(attributes); var stringifiedAttributes = _tagHelperFactsService.StringifyAttributes(attributes);
var attributeCompletions = GetAttributeCompletions(parent, containingTagNameToken.Content, selectedAttributeName, stringifiedAttributes, context.TagHelperDocumentContext, context.Options);
return attributeCompletions;
return GetAttributeCompletions(parent, containingTagNameToken.Content, selectedAttributeName, stringifiedAttributes, context.TagHelperDocumentContext, context.Options);
static bool InOrAtEndOfAttribute(SyntaxNode attributeSyntax, int absoluteIndex) static bool InOrAtEndOfAttribute(SyntaxNode attributeSyntax, int absoluteIndex)
{ {
// When we are in the middle of writing an attribute it is treated as a minimilized one, e.g.: // When we are in the middle of writing an attribute it is treated as a minimilized one, e.g.:
@ -123,10 +125,10 @@ internal class TagHelperCompletionProvider : RazorCompletionItemProvider
} }
// Invalid location for TagHelper completions. // Invalid location for TagHelper completions.
return Array.Empty<RazorCompletionItem>(); return ImmutableArray<RazorCompletionItem>.Empty;
} }
private IReadOnlyList<RazorCompletionItem> GetAttributeCompletions( private ImmutableArray<RazorCompletionItem> GetAttributeCompletions(
SyntaxNode containingAttribute, SyntaxNode containingAttribute,
string containingTagName, string containingTagName,
string? selectedAttributeName, string? selectedAttributeName,
@ -148,8 +150,9 @@ internal class TagHelperCompletionProvider : RazorCompletionItemProvider
ancestorIsTagHelper, ancestorIsTagHelper,
HtmlFactsService.IsHtmlTagName); HtmlFactsService.IsHtmlTagName);
var completionItems = new List<RazorCompletionItem>(); using var completionItems = new PooledArrayBuilder<RazorCompletionItem>();
var completionResult = _tagHelperCompletionService.GetAttributeCompletions(attributeCompletionContext); var completionResult = _tagHelperCompletionService.GetAttributeCompletions(attributeCompletionContext);
foreach (var completion in completionResult.Completions) foreach (var completion in completionResult.Completions)
{ {
var filterText = completion.Key; var filterText = completion.Key;
@ -202,13 +205,14 @@ internal class TagHelperCompletionProvider : RazorCompletionItemProvider
return descriptionInfo; return descriptionInfo;
}); });
var attributeDescriptionInfo = new AggregateBoundAttributeDescription(attributeDescriptions.ToList()); var attributeDescriptionInfo = new AggregateBoundAttributeDescription(attributeDescriptions.ToList());
razorCompletionItem.SetAttributeCompletionDescription(attributeDescriptionInfo); razorCompletionItem.SetAttributeCompletionDescription(attributeDescriptionInfo);
completionItems.Add(razorCompletionItem); completionItems.Add(razorCompletionItem);
} }
return completionItems; return completionItems.DrainToImmutable();
} }
private bool TryResolveInsertText(string baseInsertText, AttributeContext context, [NotNullWhen(true)] out string? snippetText) private bool TryResolveInsertText(string baseInsertText, AttributeContext context, [NotNullWhen(true)] out string? snippetText)
@ -231,7 +235,7 @@ internal class TagHelperCompletionProvider : RazorCompletionItemProvider
return false; return false;
} }
private IReadOnlyList<RazorCompletionItem> GetElementCompletions( private ImmutableArray<RazorCompletionItem> GetElementCompletions(
SyntaxNode containingElement, SyntaxNode containingElement,
string containingTagName, string containingTagName,
IEnumerable<KeyValuePair<string, string>> attributes, IEnumerable<KeyValuePair<string, string>> attributes,
@ -248,7 +252,7 @@ internal class TagHelperCompletionProvider : RazorCompletionItemProvider
ancestorIsTagHelper, ancestorIsTagHelper,
HtmlFactsService.IsHtmlTagName); HtmlFactsService.IsHtmlTagName);
var completionItems = new List<RazorCompletionItem>(); using var completionItems = new PooledArrayBuilder<RazorCompletionItem>();
var completionResult = _tagHelperCompletionService.GetElementCompletions(elementCompletionContext); var completionResult = _tagHelperCompletionService.GetElementCompletions(elementCompletionContext);
foreach (var completion in completionResult.Completions) foreach (var completion in completionResult.Completions)
{ {
@ -265,7 +269,7 @@ internal class TagHelperCompletionProvider : RazorCompletionItemProvider
completionItems.Add(razorCompletionItem); completionItems.Add(razorCompletionItem);
} }
return completionItems; return completionItems.DrainToImmutable();
} }
private const string BooleanTypeString = "System.Boolean"; private const string BooleanTypeString = "System.Boolean";

Просмотреть файл

@ -93,13 +93,13 @@ internal static class IServiceCollectionExtensions
services.AddSingleton<CompletionItemResolver, RazorCompletionItemResolver>(); services.AddSingleton<CompletionItemResolver, RazorCompletionItemResolver>();
services.AddSingleton<CompletionItemResolver, DelegatedCompletionItemResolver>(); services.AddSingleton<CompletionItemResolver, DelegatedCompletionItemResolver>();
services.AddSingleton<TagHelperCompletionService, LanguageServerTagHelperCompletionService>(); services.AddSingleton<TagHelperCompletionService, LanguageServerTagHelperCompletionService>();
services.AddSingleton<RazorCompletionFactsService, DefaultRazorCompletionFactsService>(); services.AddSingleton<IRazorCompletionFactsService, RazorCompletionFactsService>();
services.AddSingleton<RazorCompletionItemProvider, DirectiveCompletionItemProvider>(); services.AddSingleton<IRazorCompletionItemProvider, DirectiveCompletionItemProvider>();
services.AddSingleton<RazorCompletionItemProvider, DirectiveAttributeCompletionItemProvider>(); services.AddSingleton<IRazorCompletionItemProvider, DirectiveAttributeCompletionItemProvider>();
services.AddSingleton<RazorCompletionItemProvider, DirectiveAttributeParameterCompletionItemProvider>(); services.AddSingleton<IRazorCompletionItemProvider, DirectiveAttributeParameterCompletionItemProvider>();
services.AddSingleton<RazorCompletionItemProvider, DirectiveAttributeTransitionCompletionItemProvider>(); services.AddSingleton<IRazorCompletionItemProvider, DirectiveAttributeTransitionCompletionItemProvider>();
services.AddSingleton<RazorCompletionItemProvider, MarkupTransitionCompletionItemProvider>(); services.AddSingleton<IRazorCompletionItemProvider, MarkupTransitionCompletionItemProvider>();
services.AddSingleton<RazorCompletionItemProvider, TagHelperCompletionProvider>(); services.AddSingleton<IRazorCompletionItemProvider, TagHelperCompletionProvider>();
} }
public static void AddDiagnosticServices(this IServiceCollection services) public static void AddDiagnosticServices(this IServiceCollection services)

Просмотреть файл

@ -1,50 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
namespace Microsoft.CodeAnalysis.Razor.Completion;
[Shared]
[Export(typeof(RazorCompletionFactsService))]
internal class DefaultRazorCompletionFactsService : RazorCompletionFactsService
{
private readonly IReadOnlyList<RazorCompletionItemProvider> _completionItemProviders;
[ImportingConstructor]
public DefaultRazorCompletionFactsService([ImportMany] IEnumerable<RazorCompletionItemProvider> completionItemProviders)
{
if (completionItemProviders is null)
{
throw new ArgumentNullException(nameof(completionItemProviders));
}
_completionItemProviders = completionItemProviders.ToArray();
}
public override IReadOnlyList<RazorCompletionItem> GetCompletionItems(RazorCompletionContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.TagHelperDocumentContext is null)
{
throw new ArgumentNullException(nameof(context.TagHelperDocumentContext));
}
var completions = new List<RazorCompletionItem>();
for (var i = 0; i < _completionItemProviders.Count; i++)
{
var completionItemProvider = _completionItemProviders[i];
var items = completionItemProvider.GetCompletionItems(context);
completions.AddRange(items);
}
return completions;
}
}

Просмотреть файл

@ -5,20 +5,20 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition; using System.Composition;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.CodeAnalysis.Razor.Tooltip; using Microsoft.CodeAnalysis.Razor.Tooltip;
using Microsoft.VisualStudio.Editor.Razor; using Microsoft.VisualStudio.Editor.Razor;
namespace Microsoft.CodeAnalysis.Razor.Completion; namespace Microsoft.CodeAnalysis.Razor.Completion;
[Shared] [Shared]
[Export(typeof(RazorCompletionItemProvider))] [Export(typeof(IRazorCompletionItemProvider))]
internal class DirectiveAttributeCompletionItemProvider : DirectiveAttributeCompletionItemProviderBase internal class DirectiveAttributeCompletionItemProvider : DirectiveAttributeCompletionItemProviderBase
{ {
private static readonly RazorCompletionItem[] s_noDirectiveAttributeCompletionItems = Array.Empty<RazorCompletionItem>();
private readonly TagHelperFactsService _tagHelperFactsService; private readonly TagHelperFactsService _tagHelperFactsService;
[ImportingConstructor] [ImportingConstructor]
@ -32,7 +32,7 @@ internal class DirectiveAttributeCompletionItemProvider : DirectiveAttributeComp
_tagHelperFactsService = tagHelperFactsService; _tagHelperFactsService = tagHelperFactsService;
} }
public override IReadOnlyList<RazorCompletionItem> GetCompletionItems(RazorCompletionContext context) public override ImmutableArray<RazorCompletionItem> GetCompletionItems(RazorCompletionContext context)
{ {
if (context is null) if (context is null)
{ {
@ -47,31 +47,31 @@ internal class DirectiveAttributeCompletionItemProvider : DirectiveAttributeComp
if (!FileKinds.IsComponent(context.SyntaxTree.Options.FileKind)) if (!FileKinds.IsComponent(context.SyntaxTree.Options.FileKind))
{ {
// Directive attributes are only supported in components // Directive attributes are only supported in components
return s_noDirectiveAttributeCompletionItems; return ImmutableArray<RazorCompletionItem>.Empty;
} }
var owner = context.Owner; var owner = context.Owner;
if (owner is null) if (owner is null)
{ {
return s_noDirectiveAttributeCompletionItems; return ImmutableArray<RazorCompletionItem>.Empty;
} }
if (!TryGetAttributeInfo(owner, out _, out var attributeName, out var attributeNameLocation, out _, out _)) if (!TryGetAttributeInfo(owner, out _, out var attributeName, out var attributeNameLocation, out _, out _))
{ {
// Either we're not in an attribute or the attribute is so malformed that we can't provide proper completions. // Either we're not in an attribute or the attribute is so malformed that we can't provide proper completions.
return s_noDirectiveAttributeCompletionItems; return ImmutableArray<RazorCompletionItem>.Empty;
} }
if (!attributeNameLocation.IntersectsWith(context.AbsoluteIndex)) if (!attributeNameLocation.IntersectsWith(context.AbsoluteIndex))
{ {
// We're trying to retrieve completions on a portion of the name that is not supported (such as a parameter). // We're trying to retrieve completions on a portion of the name that is not supported (such as a parameter).
return s_noDirectiveAttributeCompletionItems; return ImmutableArray<RazorCompletionItem>.Empty;
} }
if (!TryGetElementInfo(owner.Parent.Parent, out var containingTagName, out var attributes)) if (!TryGetElementInfo(owner.Parent.Parent, out var containingTagName, out var attributes))
{ {
// This should never be the case, it means that we're operating on an attribute that doesn't have a tag. // This should never be the case, it means that we're operating on an attribute that doesn't have a tag.
return s_noDirectiveAttributeCompletionItems; return ImmutableArray<RazorCompletionItem>.Empty;
} }
// At this point we've determined that completions have been requested for the name portion of the selected attribute. // At this point we've determined that completions have been requested for the name portion of the selected attribute.
@ -86,11 +86,11 @@ internal class DirectiveAttributeCompletionItemProvider : DirectiveAttributeComp
return completionItems; return completionItems;
} }
return s_noDirectiveAttributeCompletionItems; return ImmutableArray<RazorCompletionItem>.Empty;
} }
// Internal for testing // Internal for testing
internal IReadOnlyList<RazorCompletionItem> GetAttributeCompletions( internal ImmutableArray<RazorCompletionItem> GetAttributeCompletions(
string selectedAttributeName, string selectedAttributeName,
string containingTagName, string containingTagName,
IEnumerable<string> attributes, IEnumerable<string> attributes,
@ -100,7 +100,7 @@ internal class DirectiveAttributeCompletionItemProvider : DirectiveAttributeComp
if (descriptorsForTag.Count == 0) if (descriptorsForTag.Count == 0)
{ {
// If the current tag has no possible descriptors then we can't have any directive attributes. // If the current tag has no possible descriptors then we can't have any directive attributes.
return Array.Empty<RazorCompletionItem>(); return ImmutableArray<RazorCompletionItem>.Empty;
} }
// Attributes are case sensitive when matching // Attributes are case sensitive when matching
@ -141,7 +141,8 @@ internal class DirectiveAttributeCompletionItemProvider : DirectiveAttributeComp
} }
} }
var completionItems = new List<RazorCompletionItem>(); using var completionItems = new PooledArrayBuilder<RazorCompletionItem>();
foreach (var completion in attributeCompletions) foreach (var completion in attributeCompletions)
{ {
var insertText = completion.Key; var insertText = completion.Key;
@ -173,7 +174,7 @@ internal class DirectiveAttributeCompletionItemProvider : DirectiveAttributeComp
completionItems.Add(razorCompletionItem); completionItems.Add(razorCompletionItem);
} }
return completionItems; return completionItems.DrainToImmutable();
bool TryAddCompletion(string attributeName, BoundAttributeDescriptor boundAttributeDescriptor, TagHelperDescriptor tagHelperDescriptor) bool TryAddCompletion(string attributeName, BoundAttributeDescriptor boundAttributeDescriptor, TagHelperDescriptor tagHelperDescriptor)
{ {

Просмотреть файл

@ -5,14 +5,17 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.Language.Syntax;
using RazorSyntaxList = Microsoft.AspNetCore.Razor.Language.Syntax.SyntaxList<Microsoft.AspNetCore.Razor.Language.Syntax.SyntaxNode>; using RazorSyntaxList = Microsoft.AspNetCore.Razor.Language.Syntax.SyntaxList<Microsoft.AspNetCore.Razor.Language.Syntax.SyntaxNode>;
using RazorSyntaxNode = Microsoft.AspNetCore.Razor.Language.Syntax.SyntaxNode; using RazorSyntaxNode = Microsoft.AspNetCore.Razor.Language.Syntax.SyntaxNode;
namespace Microsoft.CodeAnalysis.Razor.Completion; namespace Microsoft.CodeAnalysis.Razor.Completion;
internal abstract class DirectiveAttributeCompletionItemProviderBase : RazorCompletionItemProvider internal abstract class DirectiveAttributeCompletionItemProviderBase : IRazorCompletionItemProvider
{ {
public abstract ImmutableArray<RazorCompletionItem> GetCompletionItems(RazorCompletionContext context);
// Internal for testing // Internal for testing
internal static bool TryGetAttributeInfo( internal static bool TryGetAttributeInfo(
RazorSyntaxNode attributeLeafOwner, RazorSyntaxNode attributeLeafOwner,

Просмотреть файл

@ -5,16 +5,18 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition; using System.Composition;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.CodeAnalysis.Razor.Tooltip; using Microsoft.CodeAnalysis.Razor.Tooltip;
using Microsoft.VisualStudio.Editor.Razor; using Microsoft.VisualStudio.Editor.Razor;
namespace Microsoft.CodeAnalysis.Razor.Completion; namespace Microsoft.CodeAnalysis.Razor.Completion;
[Shared] [Shared]
[Export(typeof(RazorCompletionItemProvider))] [Export(typeof(IRazorCompletionItemProvider))]
internal class DirectiveAttributeParameterCompletionItemProvider : DirectiveAttributeCompletionItemProviderBase internal class DirectiveAttributeParameterCompletionItemProvider : DirectiveAttributeCompletionItemProviderBase
{ {
private readonly TagHelperFactsService _tagHelperFactsService; private readonly TagHelperFactsService _tagHelperFactsService;
@ -30,7 +32,7 @@ internal class DirectiveAttributeParameterCompletionItemProvider : DirectiveAttr
_tagHelperFactsService = tagHelperFactsService; _tagHelperFactsService = tagHelperFactsService;
} }
public override IReadOnlyList<RazorCompletionItem> GetCompletionItems(RazorCompletionContext context) public override ImmutableArray<RazorCompletionItem> GetCompletionItems(RazorCompletionContext context)
{ {
if (context is null) if (context is null)
{ {
@ -45,39 +47,38 @@ internal class DirectiveAttributeParameterCompletionItemProvider : DirectiveAttr
if (!FileKinds.IsComponent(context.SyntaxTree.Options.FileKind)) if (!FileKinds.IsComponent(context.SyntaxTree.Options.FileKind))
{ {
// Directive attribute parameters are only supported in components // Directive attribute parameters are only supported in components
return Array.Empty<RazorCompletionItem>(); return ImmutableArray<RazorCompletionItem>.Empty;
} }
var owner = context.Owner; var owner = context.Owner;
if (owner is null) if (owner is null)
{ {
return Array.Empty<RazorCompletionItem>(); return ImmutableArray<RazorCompletionItem>.Empty;
} }
if (!TryGetAttributeInfo(owner, out _, out var attributeName, out _, out var parameterName, out var parameterNameLocation)) if (!TryGetAttributeInfo(owner, out _, out var attributeName, out _, out var parameterName, out var parameterNameLocation))
{ {
// Either we're not in an attribute or the attribute is so malformed that we can't provide proper completions. // Either we're not in an attribute or the attribute is so malformed that we can't provide proper completions.
return Array.Empty<RazorCompletionItem>(); return ImmutableArray<RazorCompletionItem>.Empty;
} }
if (!parameterNameLocation.IntersectsWith(context.AbsoluteIndex)) if (!parameterNameLocation.IntersectsWith(context.AbsoluteIndex))
{ {
// We're trying to retrieve completions on a portion of the name that is not supported (such as the name, i.e., |@bind|:format). // We're trying to retrieve completions on a portion of the name that is not supported (such as the name, i.e., |@bind|:format).
return Array.Empty<RazorCompletionItem>(); return ImmutableArray<RazorCompletionItem>.Empty;
} }
if (!TryGetElementInfo(owner.Parent.Parent, out var containingTagName, out var attributes)) if (!TryGetElementInfo(owner.Parent.Parent, out var containingTagName, out var attributes))
{ {
// This should never be the case, it means that we're operating on an attribute that doesn't have a tag. // This should never be the case, it means that we're operating on an attribute that doesn't have a tag.
return Array.Empty<RazorCompletionItem>(); return ImmutableArray<RazorCompletionItem>.Empty;
} }
var completions = GetAttributeParameterCompletions(attributeName, parameterName, containingTagName, attributes, context.TagHelperDocumentContext); return GetAttributeParameterCompletions(attributeName, parameterName, containingTagName, attributes, context.TagHelperDocumentContext);
return completions;
} }
// Internal for testing // Internal for testing
internal IReadOnlyList<RazorCompletionItem> GetAttributeParameterCompletions( internal ImmutableArray<RazorCompletionItem> GetAttributeParameterCompletions(
string attributeName, string attributeName,
string parameterName, string parameterName,
string containingTagName, string containingTagName,
@ -88,7 +89,7 @@ internal class DirectiveAttributeParameterCompletionItemProvider : DirectiveAttr
if (descriptorsForTag.Count == 0) if (descriptorsForTag.Count == 0)
{ {
// If the current tag has no possible descriptors then we can't have any additional attributes. // If the current tag has no possible descriptors then we can't have any additional attributes.
return Array.Empty<RazorCompletionItem>(); return ImmutableArray<RazorCompletionItem>.Empty;
} }
// Attribute parameters are case sensitive when matching // Attribute parameters are case sensitive when matching
@ -130,7 +131,8 @@ internal class DirectiveAttributeParameterCompletionItemProvider : DirectiveAttr
} }
} }
var completionItems = new List<RazorCompletionItem>(); using var completionItems = new PooledArrayBuilder<RazorCompletionItem>();
foreach (var completion in attributeCompletions) foreach (var completion in attributeCompletions)
{ {
if (string.Equals(completion.Key, parameterName, StringComparison.Ordinal)) if (string.Equals(completion.Key, parameterName, StringComparison.Ordinal))
@ -150,6 +152,6 @@ internal class DirectiveAttributeParameterCompletionItemProvider : DirectiveAttr
completionItems.Add(razorCompletionItem); completionItems.Add(razorCompletionItem);
} }
return completionItems; return completionItems.DrainToImmutable();
} }
} }

Просмотреть файл

@ -5,17 +5,19 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition; using System.Composition;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Legacy; using Microsoft.AspNetCore.Razor.Language.Legacy;
using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.Language.Syntax;
using Microsoft.AspNetCore.Razor.PooledObjects;
namespace Microsoft.CodeAnalysis.Razor.Completion; namespace Microsoft.CodeAnalysis.Razor.Completion;
[Shared] [Shared]
[Export(typeof(RazorCompletionItemProvider))] [Export(typeof(IRazorCompletionItemProvider))]
internal class DirectiveCompletionItemProvider : RazorCompletionItemProvider internal class DirectiveCompletionItemProvider : IRazorCompletionItemProvider
{ {
internal static readonly IReadOnlyList<RazorCommitCharacter> SingleLineDirectiveCommitCharacters = RazorCommitCharacter.FromArray(new[] { " " }); internal static readonly IReadOnlyList<RazorCommitCharacter> SingleLineDirectiveCommitCharacters = RazorCommitCharacter.FromArray(new[] { " " });
internal static readonly IReadOnlyList<RazorCommitCharacter> BlockDirectiveCommitCharacters = RazorCommitCharacter.FromArray(new[] { " ", "{" }); internal static readonly IReadOnlyList<RazorCommitCharacter> BlockDirectiveCommitCharacters = RazorCommitCharacter.FromArray(new[] { " ", "{" });
@ -46,21 +48,22 @@ internal class DirectiveCompletionItemProvider : RazorCompletionItemProvider
["typeparam"] = ("typeparam ${1:T}$0", "typeparam T") ["typeparam"] = ("typeparam ${1:T}$0", "typeparam T")
}; };
public override IReadOnlyList<RazorCompletionItem> GetCompletionItems(RazorCompletionContext context) public ImmutableArray<RazorCompletionItem> GetCompletionItems(RazorCompletionContext context)
{ {
if (context is null) if (context is null)
{ {
throw new ArgumentNullException(nameof(context)); throw new ArgumentNullException(nameof(context));
} }
var completions = new List<RazorCompletionItem>(); using var completions = new PooledArrayBuilder<RazorCompletionItem>();
if (ShouldProvideCompletions(context)) if (ShouldProvideCompletions(context))
{ {
var directiveCompletions = GetDirectiveCompletionItems(context.SyntaxTree); var directiveCompletions = GetDirectiveCompletionItems(context.SyntaxTree);
completions.AddRange(directiveCompletions); completions.AddRange(directiveCompletions);
} }
return completions; return completions.DrainToImmutable();
} }
// Internal for testing // Internal for testing
@ -126,11 +129,13 @@ internal class DirectiveCompletionItemProvider : RazorCompletionItemProvider
} }
// Internal for testing // Internal for testing
internal static List<RazorCompletionItem> GetDirectiveCompletionItems(RazorSyntaxTree syntaxTree) internal static ImmutableArray<RazorCompletionItem> GetDirectiveCompletionItems(RazorSyntaxTree syntaxTree)
{ {
var defaultDirectives = FileKinds.IsComponent(syntaxTree.Options.FileKind) ? Array.Empty<DirectiveDescriptor>() : s_defaultDirectives; var defaultDirectives = FileKinds.IsComponent(syntaxTree.Options.FileKind) ? Array.Empty<DirectiveDescriptor>() : s_defaultDirectives;
var directives = syntaxTree.Options.Directives.Concat(defaultDirectives); var directives = syntaxTree.Options.Directives.Concat(defaultDirectives);
var completionItems = new List<RazorCompletionItem>();
using var completionItems = new PooledArrayBuilder<RazorCompletionItem>();
foreach (var directive in directives) foreach (var directive in directives)
{ {
var completionDisplayText = directive.DisplayName ?? directive.Directive; var completionDisplayText = directive.DisplayName ?? directive.Directive;
@ -164,7 +169,7 @@ internal class DirectiveCompletionItemProvider : RazorCompletionItemProvider
} }
} }
return completionItems; return completionItems.DrainToImmutable();
} }
private static IReadOnlyList<RazorCommitCharacter> GetDirectiveCommitCharacters(DirectiveKind directiveKind) private static IReadOnlyList<RazorCommitCharacter> GetDirectiveCommitCharacters(DirectiveKind directiveKind)

Просмотреть файл

@ -1,11 +1,11 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information. // Licensed under the MIT license. See License.txt in the project root for license information.
using System.Collections.Generic; using System.Collections.Immutable;
namespace Microsoft.CodeAnalysis.Razor.Completion; namespace Microsoft.CodeAnalysis.Razor.Completion;
internal abstract class RazorCompletionItemProvider internal interface IRazorCompletionFactsService
{ {
public abstract IReadOnlyList<RazorCompletionItem> GetCompletionItems(RazorCompletionContext context); ImmutableArray<RazorCompletionItem> GetCompletionItems(RazorCompletionContext razorCompletionContext);
} }

Просмотреть файл

@ -0,0 +1,11 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Collections.Immutable;
namespace Microsoft.CodeAnalysis.Razor.Completion;
internal interface IRazorCompletionItemProvider
{
ImmutableArray<RazorCompletionItem> GetCompletionItems(RazorCompletionContext context);
}

Просмотреть файл

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
using Microsoft.AspNetCore.Razor.Language.Legacy; using Microsoft.AspNetCore.Razor.Language.Legacy;
using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.Language.Syntax;
@ -11,7 +12,7 @@ using RazorSyntaxNode = Microsoft.AspNetCore.Razor.Language.Syntax.SyntaxNode;
namespace Microsoft.CodeAnalysis.Razor.Completion; namespace Microsoft.CodeAnalysis.Razor.Completion;
internal class MarkupTransitionCompletionItemProvider : RazorCompletionItemProvider internal class MarkupTransitionCompletionItemProvider : IRazorCompletionItemProvider
{ {
private static readonly IReadOnlyList<RazorCommitCharacter> s_elementCommitCharacters = RazorCommitCharacter.FromArray(new[] { ">" }); private static readonly IReadOnlyList<RazorCommitCharacter> s_elementCommitCharacters = RazorCommitCharacter.FromArray(new[] { ">" });
@ -40,15 +41,10 @@ internal class MarkupTransitionCompletionItemProvider : RazorCompletionItemProvi
public MarkupTransitionCompletionItemProvider(HtmlFactsService htmlFactsService) public MarkupTransitionCompletionItemProvider(HtmlFactsService htmlFactsService)
{ {
if (htmlFactsService is null) _htmlFactsService = htmlFactsService ?? throw new ArgumentNullException(nameof(htmlFactsService));
{
throw new ArgumentNullException(nameof(htmlFactsService));
}
_htmlFactsService = htmlFactsService;
} }
public override IReadOnlyList<RazorCompletionItem> GetCompletionItems(RazorCompletionContext context) public ImmutableArray<RazorCompletionItem> GetCompletionItems(RazorCompletionContext context)
{ {
if (context is null) if (context is null)
{ {
@ -59,12 +55,12 @@ internal class MarkupTransitionCompletionItemProvider : RazorCompletionItemProvi
if (owner is null) if (owner is null)
{ {
Debug.Fail("Owner should never be null."); Debug.Fail("Owner should never be null.");
return Array.Empty<RazorCompletionItem>(); return ImmutableArray<RazorCompletionItem>.Empty;
} }
if (!AtMarkupTransitionCompletionPoint(owner)) if (!AtMarkupTransitionCompletionPoint(owner))
{ {
return Array.Empty<RazorCompletionItem>(); return ImmutableArray<RazorCompletionItem>.Empty;
} }
var parent = owner.Parent; var parent = owner.Parent;
@ -74,11 +70,10 @@ internal class MarkupTransitionCompletionItemProvider : RazorCompletionItemProvi
if (!_htmlFactsService.TryGetElementInfo(parent, out var containingTagNameToken, out _) || if (!_htmlFactsService.TryGetElementInfo(parent, out var containingTagNameToken, out _) ||
!containingTagNameToken.Span.IntersectsWith(context.AbsoluteIndex)) !containingTagNameToken.Span.IntersectsWith(context.AbsoluteIndex))
{ {
return Array.Empty<RazorCompletionItem>(); return ImmutableArray<RazorCompletionItem>.Empty;
} }
var completions = new List<RazorCompletionItem>() { MarkupTransitionCompletionItem }; return ImmutableArray.Create(MarkupTransitionCompletionItem);
return completions;
} }
private static bool AtMarkupTransitionCompletionPoint(RazorSyntaxNode owner) private static bool AtMarkupTransitionCompletionPoint(RazorSyntaxNode owner)

Просмотреть файл

@ -1,11 +1,51 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information. // Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using Microsoft.AspNetCore.Razor.PooledObjects;
namespace Microsoft.CodeAnalysis.Razor.Completion; namespace Microsoft.CodeAnalysis.Razor.Completion;
internal abstract class RazorCompletionFactsService [Shared]
[Export(typeof(IRazorCompletionFactsService))]
internal class RazorCompletionFactsService : IRazorCompletionFactsService
{ {
public abstract IReadOnlyList<RazorCompletionItem> GetCompletionItems(RazorCompletionContext razorCompletionContext); private readonly ImmutableArray<IRazorCompletionItemProvider> _providers;
[ImportingConstructor]
public RazorCompletionFactsService([ImportMany] IEnumerable<IRazorCompletionItemProvider> providers)
{
if (providers is null)
{
throw new ArgumentNullException(nameof(providers));
}
_providers = providers.ToImmutableArray();
}
public ImmutableArray<RazorCompletionItem> GetCompletionItems(RazorCompletionContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.TagHelperDocumentContext is null)
{
throw new ArgumentNullException(nameof(context.TagHelperDocumentContext));
}
using var completions = new PooledArrayBuilder<RazorCompletionItem>();
foreach (var provider in _providers)
{
var items = provider.GetCompletionItems(context);
completions.AddRange(items);
}
return completions.DrainToImmutable();
}
} }

Просмотреть файл

@ -0,0 +1,42 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data;
namespace Microsoft.VisualStudio.Editor.Razor.Completion;
/// <summary>
/// Compares <see cref="CompletionItem"/>s by display text using the current culture.
/// </summary>
internal sealed class CompletionItemDisplayTextComparer : IComparer<CompletionItem>
{
public static readonly CompletionItemDisplayTextComparer Instance = new();
private CompletionItemDisplayTextComparer()
{
}
public int Compare(CompletionItem x, CompletionItem y)
{
var displayText1 = x?.DisplayText;
var displayText2 = y?.DisplayText;
if (displayText1 is null)
{
if (displayText2 is not null)
{
return -1;
}
return 0;
}
else if (displayText2 is null)
{
return 1;
}
return StringComparer.CurrentCulture.Compare(displayText1, displayText2);
}
}

Просмотреть файл

@ -1,115 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Composition;
using Microsoft.CodeAnalysis.Razor.Tooltip;
using Microsoft.VisualStudio.Core.Imaging;
using Microsoft.VisualStudio.Text.Adornments;
namespace Microsoft.VisualStudio.Editor.Razor.Completion;
[Shared]
[Export(typeof(VisualStudioDescriptionFactory))]
internal class DefaultVisualStudioDescriptionFactory : VisualStudioDescriptionFactory
{
// Internal for testing
internal static readonly ContainerElement SeparatorElement = new(
ContainerElementStyle.Wrapped,
new ClassifiedTextElement(
new ClassifiedTextRun(PredefinedClassificationNames.Comment, "------------")));
// Hardcoding the Guid here to avoid a reference to Microsoft.VisualStudio.ImageCatalog.dll
// that is not present in Visual Studio for Mac
private static readonly Guid s_imageCatalogGuid = new("{ae27a6b0-e345-4288-96df-5eaf394ee369}");
private static readonly ImageElement s_propertyGlyph = new(
new ImageId(s_imageCatalogGuid, 2429), // KnownImageIds.Type = 2429
"Razor Attribute Glyph");
private static readonly ClassifiedTextRun s_spaceLiteral = new(PredefinedClassificationNames.Literal, " ");
private static readonly ClassifiedTextRun s_dotLiteral = new(PredefinedClassificationNames.Literal, ".");
public override ContainerElement CreateClassifiedDescription(AggregateBoundAttributeDescription completionDescription)
{
if (completionDescription is null)
{
throw new ArgumentNullException(nameof(completionDescription));
}
var descriptionElements = new List<object>();
foreach (var descriptionInfo in completionDescription.DescriptionInfos)
{
if (descriptionElements.Count > 0)
{
descriptionElements.Add(SeparatorElement);
}
var returnTypeClassification = PredefinedClassificationNames.Type;
if (TypeNameStringResolver.TryGetSimpleName(descriptionInfo.ReturnTypeName, out var returnTypeName))
{
returnTypeClassification = PredefinedClassificationNames.Keyword;
}
else
{
returnTypeName = descriptionInfo.ReturnTypeName;
}
var tagHelperTypeName = descriptionInfo.TypeName;
var tagHelperTypeNamePrefix = string.Empty;
var tagHelperTypeNameProper = tagHelperTypeName;
var lastDot = tagHelperTypeName.LastIndexOf('.');
if (lastDot > 0)
{
var afterLastDot = lastDot + 1;
// We're pulling apart the type name so the prefix looks like:
//
// Microsoft.AspnetCore.Components.
tagHelperTypeNamePrefix = tagHelperTypeName[..afterLastDot];
// And the type name looks like BindBinds
tagHelperTypeNameProper = tagHelperTypeName[afterLastDot..];
}
descriptionElements.Add(
new ContainerElement(
ContainerElementStyle.Wrapped,
s_propertyGlyph,
new ClassifiedTextElement(
new ClassifiedTextRun(returnTypeClassification, returnTypeName),
s_spaceLiteral,
new ClassifiedTextRun(PredefinedClassificationNames.Literal, tagHelperTypeNamePrefix),
new ClassifiedTextRun(PredefinedClassificationNames.Type, tagHelperTypeNameProper),
s_dotLiteral,
new ClassifiedTextRun(PredefinedClassificationNames.Identifier, descriptionInfo.PropertyName))));
if (descriptionInfo.Documentation != null)
{
descriptionElements.Add(
new ContainerElement(
ContainerElementStyle.Wrapped,
new ClassifiedTextElement(
new ClassifiedTextRun(PredefinedClassificationNames.NaturalLanguage, descriptionInfo.Documentation))));
}
}
var descriptionContainer = new ContainerElement(ContainerElementStyle.Stacked, descriptionElements);
return descriptionContainer;
}
private static class PredefinedClassificationNames
{
public const string Keyword = "keyword";
public const string Literal = "literal";
public const string Type = "Type";
public const string Identifier = "identifier";
public const string Comment = "comment";
public const string NaturalLanguage = "natural language";
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.Razor.Tooltip;
using Microsoft.VisualStudio.Text.Adornments;
namespace Microsoft.VisualStudio.Editor.Razor.Completion;
internal interface IVisualStudioDescriptionFactory
{
ContainerElement CreateClassifiedDescription(AggregateBoundAttributeDescription description);
}

Просмотреть файл

@ -4,11 +4,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Legacy; using Microsoft.AspNetCore.Razor.Language.Legacy;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.Completion; using Microsoft.CodeAnalysis.Razor.Completion;
using Microsoft.CodeAnalysis.Razor.Tooltip; using Microsoft.CodeAnalysis.Razor.Tooltip;
@ -38,45 +38,25 @@ internal class RazorDirectiveAttributeCompletionSource : IAsyncCompletionSource
}.ToImmutableArray(); }.ToImmutableArray();
private readonly VisualStudioRazorParser _parser; private readonly VisualStudioRazorParser _parser;
private readonly RazorCompletionFactsService _completionFactsService; private readonly IRazorCompletionFactsService _completionFactsService;
private readonly ICompletionBroker _completionBroker; private readonly ICompletionBroker _completionBroker;
private readonly VisualStudioDescriptionFactory _descriptionFactory; private readonly IVisualStudioDescriptionFactory _descriptionFactory;
private readonly JoinableTaskFactory _joinableTaskFactory; private readonly JoinableTaskFactory _joinableTaskFactory;
private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
public RazorDirectiveAttributeCompletionSource( public RazorDirectiveAttributeCompletionSource(
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
VisualStudioRazorParser parser, VisualStudioRazorParser parser,
RazorCompletionFactsService completionFactsService, IRazorCompletionFactsService completionFactsService,
ICompletionBroker completionBroker, ICompletionBroker completionBroker,
VisualStudioDescriptionFactory descriptionFactory, IVisualStudioDescriptionFactory descriptionFactory,
JoinableTaskFactory joinableTaskFactory) JoinableTaskFactory joinableTaskFactory)
{ {
if (projectSnapshotManagerDispatcher is null) _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher ?? throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
{ _parser = parser ?? throw new ArgumentNullException(nameof(parser));
throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); _completionFactsService = completionFactsService ?? throw new ArgumentNullException(nameof(completionFactsService));
}
if (parser is null)
{
throw new ArgumentNullException(nameof(parser));
}
if (completionFactsService is null)
{
throw new ArgumentNullException(nameof(completionFactsService));
}
if (descriptionFactory is null)
{
throw new ArgumentNullException(nameof(descriptionFactory));
}
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher;
_parser = parser;
_completionFactsService = completionFactsService;
_completionBroker = completionBroker; _completionBroker = completionBroker;
_descriptionFactory = descriptionFactory; _descriptionFactory = descriptionFactory ?? throw new ArgumentNullException(nameof(descriptionFactory));
_joinableTaskFactory = joinableTaskFactory; _joinableTaskFactory = joinableTaskFactory;
} }
@ -99,7 +79,7 @@ internal class RazorDirectiveAttributeCompletionSource : IAsyncCompletionSource
var razorCompletionContext = new RazorCompletionContext(absoluteIndex, owner, syntaxTree, tagHelperDocumentContext); var razorCompletionContext = new RazorCompletionContext(absoluteIndex, owner, syntaxTree, tagHelperDocumentContext);
var razorCompletionItems = _completionFactsService.GetCompletionItems(razorCompletionContext); var razorCompletionItems = _completionFactsService.GetCompletionItems(razorCompletionContext);
if (razorCompletionItems.Count == 0) if (razorCompletionItems.Length == 0)
{ {
return CompletionContext.Empty; return CompletionContext.Empty;
} }
@ -121,8 +101,9 @@ internal class RazorDirectiveAttributeCompletionSource : IAsyncCompletionSource
activeSession.Dismiss(); activeSession.Dismiss();
} }
var completionItems = new List<CompletionItem>(); using var _ = ArrayBuilderPool<CompletionItem>.GetPooledObject(out var completionItems);
var completionItemKinds = new HashSet<RazorCompletionItemKind>(); var completionItemKinds = new HashSet<RazorCompletionItemKind>();
foreach (var razorCompletionItem in razorCompletionItems) foreach (var razorCompletionItem in razorCompletionItems)
{ {
if (razorCompletionItem.Kind != RazorCompletionItemKind.DirectiveAttribute && if (razorCompletionItem.Kind != RazorCompletionItemKind.DirectiveAttribute &&
@ -150,9 +131,10 @@ internal class RazorDirectiveAttributeCompletionSource : IAsyncCompletionSource
} }
session.Properties.SetCompletionItemKinds(completionItemKinds); session.Properties.SetCompletionItemKinds(completionItemKinds);
var orderedCompletionItems = completionItems.OrderBy(item => item.DisplayText);
var context = new CompletionContext(orderedCompletionItems.ToImmutableArray()); completionItems.Sort(CompletionItemDisplayTextComparer.Instance);
return context;
return new CompletionContext(completionItems.ToImmutable());
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {

Просмотреть файл

@ -23,50 +23,24 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion;
internal class RazorDirectiveAttributeCompletionSourceProvider : IAsyncCompletionSourceProvider internal class RazorDirectiveAttributeCompletionSourceProvider : IAsyncCompletionSourceProvider
{ {
private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
private readonly RazorCompletionFactsService _completionFactsService; private readonly IRazorCompletionFactsService _completionFactsService;
private readonly ICompletionBroker _completionBroker; private readonly ICompletionBroker _completionBroker;
private readonly VisualStudioDescriptionFactory _descriptionFactory; private readonly IVisualStudioDescriptionFactory _descriptionFactory;
private readonly JoinableTaskContext _joinableTaskContext; private readonly JoinableTaskContext _joinableTaskContext;
[ImportingConstructor] [ImportingConstructor]
public RazorDirectiveAttributeCompletionSourceProvider( public RazorDirectiveAttributeCompletionSourceProvider(
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
RazorCompletionFactsService completionFactsService, IRazorCompletionFactsService completionFactsService,
IAsyncCompletionBroker asyncCoompletionBroker,
ICompletionBroker completionBroker, ICompletionBroker completionBroker,
VisualStudioDescriptionFactory descriptionFactory, IVisualStudioDescriptionFactory descriptionFactory,
JoinableTaskContext joinableTaskContext) JoinableTaskContext joinableTaskContext)
{ {
if (projectSnapshotManagerDispatcher is null) _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher ?? throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
{ _completionFactsService = completionFactsService ?? throw new ArgumentNullException(nameof(completionFactsService));
throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); _completionBroker = completionBroker ?? throw new ArgumentNullException(nameof(completionBroker));
} _descriptionFactory = descriptionFactory ?? throw new ArgumentNullException(nameof(descriptionFactory));
_joinableTaskContext = joinableTaskContext ?? throw new ArgumentNullException(nameof(joinableTaskContext));
if (completionFactsService is null)
{
throw new ArgumentNullException(nameof(completionFactsService));
}
if (asyncCoompletionBroker is null)
{
throw new ArgumentNullException(nameof(asyncCoompletionBroker));
}
if (descriptionFactory is null)
{
throw new ArgumentNullException(nameof(descriptionFactory));
}
if (joinableTaskContext is null)
{
throw new ArgumentNullException(nameof(joinableTaskContext));
}
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher;
_completionFactsService = completionFactsService;
_completionBroker = completionBroker;
_descriptionFactory = descriptionFactory;
_joinableTaskContext = joinableTaskContext;
} }
public IAsyncCompletionSource? GetOrCreate(ITextView textView) public IAsyncCompletionSource? GetOrCreate(ITextView textView)
@ -96,13 +70,12 @@ internal class RazorDirectiveAttributeCompletionSourceProvider : IAsyncCompletio
return null; return null;
} }
var completionSource = new RazorDirectiveAttributeCompletionSource( return new RazorDirectiveAttributeCompletionSource(
_projectSnapshotManagerDispatcher, _projectSnapshotManagerDispatcher,
parser, parser,
_completionFactsService, _completionFactsService,
_completionBroker, _completionBroker,
_descriptionFactory, _descriptionFactory,
_joinableTaskContext.Factory); _joinableTaskContext.Factory);
return completionSource;
} }
} }

Просмотреть файл

@ -2,12 +2,12 @@
// Licensed under the MIT license. See License.txt in the project root for license information. // Licensed under the MIT license. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Legacy; using Microsoft.AspNetCore.Razor.Language.Legacy;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.CodeAnalysis.Razor.Completion; using Microsoft.CodeAnalysis.Razor.Completion;
using Microsoft.VisualStudio.Core.Imaging; using Microsoft.VisualStudio.Core.Imaging;
using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion;
@ -33,11 +33,11 @@ internal class RazorDirectiveCompletionSource : IAsyncCompletionSource
// Internal for testing // Internal for testing
internal readonly VisualStudioRazorParser Parser; internal readonly VisualStudioRazorParser Parser;
private readonly RazorCompletionFactsService _completionFactsService; private readonly IRazorCompletionFactsService _completionFactsService;
public RazorDirectiveCompletionSource( public RazorDirectiveCompletionSource(
VisualStudioRazorParser parser, VisualStudioRazorParser parser,
RazorCompletionFactsService completionFactsService) IRazorCompletionFactsService completionFactsService)
{ {
if (parser is null) if (parser is null)
{ {
@ -77,7 +77,8 @@ internal class RazorDirectiveCompletionSource : IAsyncCompletionSource
var razorCompletionContext = new RazorCompletionContext(absoluteIndex, owner, syntaxTree, tagHelperDocumentContext); var razorCompletionContext = new RazorCompletionContext(absoluteIndex, owner, syntaxTree, tagHelperDocumentContext);
var razorCompletionItems = _completionFactsService.GetCompletionItems(razorCompletionContext); var razorCompletionItems = _completionFactsService.GetCompletionItems(razorCompletionContext);
var completionItems = new List<CompletionItem>(); using var _ = ArrayBuilderPool<CompletionItem>.GetPooledObject(out var completionItems);
foreach (var razorCompletionItem in razorCompletionItems) foreach (var razorCompletionItem in razorCompletionItems)
{ {
if (razorCompletionItem.Kind != RazorCompletionItemKind.Directive) if (razorCompletionItem.Kind != RazorCompletionItemKind.Directive)
@ -96,13 +97,13 @@ internal class RazorDirectiveCompletionSource : IAsyncCompletionSource
suffix: string.Empty, suffix: string.Empty,
sortText: razorCompletionItem.DisplayText, sortText: razorCompletionItem.DisplayText,
attributeIcons: ImmutableArray<ImageElement>.Empty); attributeIcons: ImmutableArray<ImageElement>.Empty);
var completionDescription = razorCompletionItem.GetDirectiveCompletionDescription(); var completionDescription = razorCompletionItem.GetDirectiveCompletionDescription();
completionItem.Properties.AddProperty(DescriptionKey, completionDescription); completionItem.Properties.AddProperty(DescriptionKey, completionDescription);
completionItems.Add(completionItem); completionItems.Add(completionItem);
} }
var context = new CompletionContext(completionItems.ToImmutableArray()); return new CompletionContext(completionItems.ToImmutable());
return context;
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {

Просмотреть файл

@ -20,10 +20,10 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion;
[ContentType(RazorConstants.LegacyCoreContentType)] [ContentType(RazorConstants.LegacyCoreContentType)]
internal class RazorDirectiveCompletionSourceProvider : IAsyncCompletionSourceProvider internal class RazorDirectiveCompletionSourceProvider : IAsyncCompletionSourceProvider
{ {
private readonly RazorCompletionFactsService _completionFactsService; private readonly IRazorCompletionFactsService _completionFactsService;
[ImportingConstructor] [ImportingConstructor]
public RazorDirectiveCompletionSourceProvider(RazorCompletionFactsService completionFactsService) public RazorDirectiveCompletionSourceProvider(IRazorCompletionFactsService completionFactsService)
{ {
if (completionFactsService is null) if (completionFactsService is null)
{ {

Просмотреть файл

@ -1,12 +1,114 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information. // Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Composition;
using Microsoft.CodeAnalysis.Razor.Tooltip; using Microsoft.CodeAnalysis.Razor.Tooltip;
using Microsoft.VisualStudio.Core.Imaging;
using Microsoft.VisualStudio.Text.Adornments; using Microsoft.VisualStudio.Text.Adornments;
namespace Microsoft.VisualStudio.Editor.Razor.Completion; namespace Microsoft.VisualStudio.Editor.Razor.Completion;
internal abstract class VisualStudioDescriptionFactory [Shared]
[Export(typeof(IVisualStudioDescriptionFactory))]
internal class VisualStudioDescriptionFactory : IVisualStudioDescriptionFactory
{ {
public abstract ContainerElement CreateClassifiedDescription(AggregateBoundAttributeDescription completionDescription); // Internal for testing
internal static readonly ContainerElement SeparatorElement = new(
ContainerElementStyle.Wrapped,
new ClassifiedTextElement(
new ClassifiedTextRun(PredefinedClassificationNames.Comment, "------------")));
// Hardcoding the Guid here to avoid a reference to Microsoft.VisualStudio.ImageCatalog.dll
// that is not present in Visual Studio for Mac
private static readonly Guid s_imageCatalogGuid = new("{ae27a6b0-e345-4288-96df-5eaf394ee369}");
private static readonly ImageElement s_propertyGlyph = new(
new ImageId(s_imageCatalogGuid, 2429), // KnownImageIds.Type = 2429
"Razor Attribute Glyph");
private static readonly ClassifiedTextRun s_spaceLiteral = new(PredefinedClassificationNames.Literal, " ");
private static readonly ClassifiedTextRun s_dotLiteral = new(PredefinedClassificationNames.Literal, ".");
public ContainerElement CreateClassifiedDescription(AggregateBoundAttributeDescription description)
{
if (description is null)
{
throw new ArgumentNullException(nameof(description));
}
var descriptionElements = new List<object>();
foreach (var descriptionInfo in description.DescriptionInfos)
{
if (descriptionElements.Count > 0)
{
descriptionElements.Add(SeparatorElement);
}
var returnTypeClassification = PredefinedClassificationNames.Type;
if (TypeNameStringResolver.TryGetSimpleName(descriptionInfo.ReturnTypeName, out var returnTypeName))
{
returnTypeClassification = PredefinedClassificationNames.Keyword;
}
else
{
returnTypeName = descriptionInfo.ReturnTypeName;
}
var tagHelperTypeName = descriptionInfo.TypeName;
var tagHelperTypeNamePrefix = string.Empty;
var tagHelperTypeNameProper = tagHelperTypeName;
var lastDot = tagHelperTypeName.LastIndexOf('.');
if (lastDot > 0)
{
var afterLastDot = lastDot + 1;
// We're pulling apart the type name so the prefix looks like:
//
// Microsoft.AspnetCore.Components.
tagHelperTypeNamePrefix = tagHelperTypeName[..afterLastDot];
// And the type name looks like BindBinds
tagHelperTypeNameProper = tagHelperTypeName[afterLastDot..];
}
descriptionElements.Add(
new ContainerElement(
ContainerElementStyle.Wrapped,
s_propertyGlyph,
new ClassifiedTextElement(
new ClassifiedTextRun(returnTypeClassification, returnTypeName),
s_spaceLiteral,
new ClassifiedTextRun(PredefinedClassificationNames.Literal, tagHelperTypeNamePrefix),
new ClassifiedTextRun(PredefinedClassificationNames.Type, tagHelperTypeNameProper),
s_dotLiteral,
new ClassifiedTextRun(PredefinedClassificationNames.Identifier, descriptionInfo.PropertyName))));
if (descriptionInfo.Documentation is { } documentation)
{
descriptionElements.Add(
new ContainerElement(
ContainerElementStyle.Wrapped,
new ClassifiedTextElement(
new ClassifiedTextRun(PredefinedClassificationNames.NaturalLanguage, documentation))));
}
}
return new ContainerElement(ContainerElementStyle.Stacked, descriptionElements);
}
private static class PredefinedClassificationNames
{
public const string Keyword = "keyword";
public const string Literal = "literal";
public const string Type = "Type";
public const string Identifier = "identifier";
public const string Comment = "comment";
public const string NaturalLanguage = "natural language";
}
} }

Просмотреть файл

@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion;
public class LegacyRazorCompletionEndpointTest : LanguageServerTestBase public class LegacyRazorCompletionEndpointTest : LanguageServerTestBase
{ {
private readonly RazorCompletionFactsService _completionFactsService; private readonly IRazorCompletionFactsService _completionFactsService;
private readonly CompletionListCache _completionListCache; private readonly CompletionListCache _completionListCache;
private readonly VSInternalClientCapabilities _clientCapabilities; private readonly VSInternalClientCapabilities _clientCapabilities;
@ -36,7 +36,7 @@ public class LegacyRazorCompletionEndpointTest : LanguageServerTestBase
var tagHelperFactsService = new DefaultTagHelperFactsService(); var tagHelperFactsService = new DefaultTagHelperFactsService();
var tagHelperCompletionService = new LanguageServerTagHelperCompletionService(tagHelperFactsService); var tagHelperCompletionService = new LanguageServerTagHelperCompletionService(tagHelperFactsService);
var completionProviders = new RazorCompletionItemProvider[] var completionProviders = new IRazorCompletionItemProvider[]
{ {
new DirectiveCompletionItemProvider(), new DirectiveCompletionItemProvider(),
new DirectiveAttributeCompletionItemProvider(tagHelperFactsService), new DirectiveAttributeCompletionItemProvider(tagHelperFactsService),
@ -44,7 +44,7 @@ public class LegacyRazorCompletionEndpointTest : LanguageServerTestBase
new TagHelperCompletionProvider(tagHelperCompletionService, new DefaultHtmlFactsService(), tagHelperFactsService, TestRazorLSPOptionsMonitor.Create()) new TagHelperCompletionProvider(tagHelperCompletionService, new DefaultHtmlFactsService(), tagHelperFactsService, TestRazorLSPOptionsMonitor.Create())
}; };
_completionFactsService = new DefaultRazorCompletionFactsService(completionProviders); _completionFactsService = new RazorCompletionFactsService(completionProviders);
_completionListCache = new CompletionListCache(); _completionListCache = new CompletionListCache();
_clientCapabilities = new VSInternalClientCapabilities() _clientCapabilities = new VSInternalClientCapabilities()
{ {

Просмотреть файл

@ -4,7 +4,7 @@
#nullable disable #nullable disable
using System; using System;
using System.Collections.Generic; using System.Collections.Immutable;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -27,7 +27,6 @@ public class LegacyRazorCompletionResolveEndpointTest : LanguageServerTestBase
private readonly CompletionListCache _completionListCache; private readonly CompletionListCache _completionListCache;
private readonly VSInternalCompletionSetting _completionCapability; private readonly VSInternalCompletionSetting _completionCapability;
private readonly VSInternalClientCapabilities _defaultClientCapability; private readonly VSInternalClientCapabilities _defaultClientCapability;
private readonly VSInternalClientCapabilities _vsClientCapability;
public LegacyRazorCompletionResolveEndpointTest(ITestOutputHelper testOutput) public LegacyRazorCompletionResolveEndpointTest(ITestOutputHelper testOutput)
: base(testOutput) : base(testOutput)
@ -50,15 +49,6 @@ public class LegacyRazorCompletionResolveEndpointTest : LanguageServerTestBase
Completion = _completionCapability, Completion = _completionCapability,
}, },
}; };
_vsClientCapability = new VSInternalClientCapabilities()
{
TextDocument = new TextDocumentClientCapabilities()
{
Completion = _completionCapability,
},
SupportsVisualStudioExtensions = true,
};
} }
[Fact] [Fact]
@ -69,7 +59,7 @@ public class LegacyRazorCompletionResolveEndpointTest : LanguageServerTestBase
endpoint.ApplyCapabilities(new(), _defaultClientCapability); endpoint.ApplyCapabilities(new(), _defaultClientCapability);
var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.Directive); var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.Directive);
razorCompletionItem.SetDirectiveCompletionDescription(new DirectiveCompletionDescription("Test directive")); razorCompletionItem.SetDirectiveCompletionDescription(new DirectiveCompletionDescription("Test directive"));
var completionList = CreateLSPCompletionList(new[] { razorCompletionItem }); var completionList = CreateLSPCompletionList(razorCompletionItem);
var completionItem = completionList.Items.Single(); var completionItem = completionList.Items.Single();
var parameters = ConvertToBridgedItem(completionItem); var parameters = ConvertToBridgedItem(completionItem);
var requestContext = CreateRazorRequestContext(documentContext: null); var requestContext = CreateRazorRequestContext(documentContext: null);
@ -89,7 +79,7 @@ public class LegacyRazorCompletionResolveEndpointTest : LanguageServerTestBase
endpoint.ApplyCapabilities(new(), _defaultClientCapability); endpoint.ApplyCapabilities(new(), _defaultClientCapability);
var razorCompletionItem = new RazorCompletionItem("@...", "@", RazorCompletionItemKind.MarkupTransition); var razorCompletionItem = new RazorCompletionItem("@...", "@", RazorCompletionItemKind.MarkupTransition);
razorCompletionItem.SetMarkupTransitionCompletionDescription(new MarkupTransitionCompletionDescription("Test description")); razorCompletionItem.SetMarkupTransitionCompletionDescription(new MarkupTransitionCompletionDescription("Test description"));
var completionList = CreateLSPCompletionList(new[] { razorCompletionItem }); var completionList = CreateLSPCompletionList(razorCompletionItem);
var completionItem = completionList.Items.Single(); var completionItem = completionList.Items.Single();
var parameters = ConvertToBridgedItem(completionItem); var parameters = ConvertToBridgedItem(completionItem);
var requestContext = CreateRazorRequestContext(documentContext: null); var requestContext = CreateRazorRequestContext(documentContext: null);
@ -117,7 +107,7 @@ public class LegacyRazorCompletionResolveEndpointTest : LanguageServerTestBase
endpoint.ApplyCapabilities(new(), _defaultClientCapability); endpoint.ApplyCapabilities(new(), _defaultClientCapability);
var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.DirectiveAttribute); var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.DirectiveAttribute);
razorCompletionItem.SetAttributeCompletionDescription(new AggregateBoundAttributeDescription(Array.Empty<BoundAttributeDescriptionInfo>())); razorCompletionItem.SetAttributeCompletionDescription(new AggregateBoundAttributeDescription(Array.Empty<BoundAttributeDescriptionInfo>()));
var completionList = CreateLSPCompletionList(new[] { razorCompletionItem }); var completionList = CreateLSPCompletionList(razorCompletionItem);
var completionItem = completionList.Items.Single(); var completionItem = completionList.Items.Single();
var parameters = ConvertToBridgedItem(completionItem); var parameters = ConvertToBridgedItem(completionItem);
var requestContext = CreateRazorRequestContext(documentContext: null); var requestContext = CreateRazorRequestContext(documentContext: null);
@ -145,7 +135,7 @@ public class LegacyRazorCompletionResolveEndpointTest : LanguageServerTestBase
endpoint.ApplyCapabilities(new(), _defaultClientCapability); endpoint.ApplyCapabilities(new(), _defaultClientCapability);
var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.DirectiveAttributeParameter); var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.DirectiveAttributeParameter);
razorCompletionItem.SetAttributeCompletionDescription(new AggregateBoundAttributeDescription(Array.Empty<BoundAttributeDescriptionInfo>())); razorCompletionItem.SetAttributeCompletionDescription(new AggregateBoundAttributeDescription(Array.Empty<BoundAttributeDescriptionInfo>()));
var completionList = CreateLSPCompletionList(new[] { razorCompletionItem }); var completionList = CreateLSPCompletionList(razorCompletionItem);
var completionItem = completionList.Items.Single(); var completionItem = completionList.Items.Single();
var parameters = ConvertToBridgedItem(completionItem); var parameters = ConvertToBridgedItem(completionItem);
var requestContext = CreateRazorRequestContext(documentContext: null); var requestContext = CreateRazorRequestContext(documentContext: null);
@ -173,7 +163,7 @@ public class LegacyRazorCompletionResolveEndpointTest : LanguageServerTestBase
endpoint.ApplyCapabilities(new(), _defaultClientCapability); endpoint.ApplyCapabilities(new(), _defaultClientCapability);
var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.TagHelperElement); var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.TagHelperElement);
razorCompletionItem.SetTagHelperElementDescriptionInfo(new AggregateBoundElementDescription(Array.Empty<BoundElementDescriptionInfo>())); razorCompletionItem.SetTagHelperElementDescriptionInfo(new AggregateBoundElementDescription(Array.Empty<BoundElementDescriptionInfo>()));
var completionList = CreateLSPCompletionList(new[] { razorCompletionItem }); var completionList = CreateLSPCompletionList(razorCompletionItem);
var completionItem = completionList.Items.Single(); var completionItem = completionList.Items.Single();
var parameters = ConvertToBridgedItem(completionItem); var parameters = ConvertToBridgedItem(completionItem);
var requestContext = CreateRazorRequestContext(documentContext: null); var requestContext = CreateRazorRequestContext(documentContext: null);
@ -201,7 +191,7 @@ public class LegacyRazorCompletionResolveEndpointTest : LanguageServerTestBase
endpoint.ApplyCapabilities(new(), _defaultClientCapability); endpoint.ApplyCapabilities(new(), _defaultClientCapability);
var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.TagHelperAttribute); var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.TagHelperAttribute);
razorCompletionItem.SetAttributeCompletionDescription(new AggregateBoundAttributeDescription(Array.Empty<BoundAttributeDescriptionInfo>())); razorCompletionItem.SetAttributeCompletionDescription(new AggregateBoundAttributeDescription(Array.Empty<BoundAttributeDescriptionInfo>()));
var completionList = CreateLSPCompletionList(new[] { razorCompletionItem }); var completionList = CreateLSPCompletionList(razorCompletionItem);
var completionItem = completionList.Items.Single(); var completionItem = completionList.Items.Single();
var parameters = ConvertToBridgedItem(completionItem); var parameters = ConvertToBridgedItem(completionItem);
var requestContext = CreateRazorRequestContext(documentContext: null); var requestContext = CreateRazorRequestContext(documentContext: null);
@ -238,9 +228,9 @@ public class LegacyRazorCompletionResolveEndpointTest : LanguageServerTestBase
Assert.Null(newCompletionItem.Documentation); Assert.Null(newCompletionItem.Documentation);
} }
private VSInternalCompletionList CreateLSPCompletionList(IReadOnlyList<RazorCompletionItem> razorCompletionItems) private VSInternalCompletionList CreateLSPCompletionList(params RazorCompletionItem[] razorCompletionItems)
{ {
var completionList = LegacyRazorCompletionEndpoint.CreateLSPCompletionList(razorCompletionItems, _defaultClientCapability); var completionList = LegacyRazorCompletionEndpoint.CreateLSPCompletionList(razorCompletionItems.ToImmutableArray(), _defaultClientCapability);
var resultId = _completionListCache.Add(completionList, razorCompletionItems); var resultId = _completionListCache.Add(completionList, razorCompletionItems);
completionList.SetResultId(resultId, completionSetting: null); completionList.SetResultId(resultId, completionSetting: null);
return completionList; return completionList;

Просмотреть файл

@ -4,7 +4,7 @@
#nullable disable #nullable disable
using System; using System;
using System.Collections.Generic; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.LanguageServer.Tooltip; using Microsoft.AspNetCore.Razor.LanguageServer.Tooltip;
@ -70,7 +70,7 @@ public class RazorCompletionItemResolverTest : LanguageServerTestBase
var resolver = new RazorCompletionItemResolver(_lspTagHelperTooltipFactory, _vsLspTagHelperTooltipFactory); var resolver = new RazorCompletionItemResolver(_lspTagHelperTooltipFactory, _vsLspTagHelperTooltipFactory);
var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.Directive); var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.Directive);
razorCompletionItem.SetDirectiveCompletionDescription(new DirectiveCompletionDescription("Test directive")); razorCompletionItem.SetDirectiveCompletionDescription(new DirectiveCompletionDescription("Test directive"));
var completionList = CreateLSPCompletionList(new[] { razorCompletionItem }); var completionList = CreateLSPCompletionList(razorCompletionItem);
var completionItem = completionList.Items.Single() as VSInternalCompletionItem; var completionItem = completionList.Items.Single() as VSInternalCompletionItem;
// Act // Act
@ -88,7 +88,7 @@ public class RazorCompletionItemResolverTest : LanguageServerTestBase
var resolver = new RazorCompletionItemResolver(_lspTagHelperTooltipFactory, _vsLspTagHelperTooltipFactory); var resolver = new RazorCompletionItemResolver(_lspTagHelperTooltipFactory, _vsLspTagHelperTooltipFactory);
var razorCompletionItem = new RazorCompletionItem("@...", "@", RazorCompletionItemKind.MarkupTransition); var razorCompletionItem = new RazorCompletionItem("@...", "@", RazorCompletionItemKind.MarkupTransition);
razorCompletionItem.SetMarkupTransitionCompletionDescription(new MarkupTransitionCompletionDescription("Test description")); razorCompletionItem.SetMarkupTransitionCompletionDescription(new MarkupTransitionCompletionDescription("Test description"));
var completionList = CreateLSPCompletionList(new[] { razorCompletionItem }); var completionList = CreateLSPCompletionList(razorCompletionItem);
var completionItem = completionList.Items.Single() as VSInternalCompletionItem; var completionItem = completionList.Items.Single() as VSInternalCompletionItem;
// Act // Act
@ -106,7 +106,7 @@ public class RazorCompletionItemResolverTest : LanguageServerTestBase
var resolver = new RazorCompletionItemResolver(_lspTagHelperTooltipFactory, _vsLspTagHelperTooltipFactory); var resolver = new RazorCompletionItemResolver(_lspTagHelperTooltipFactory, _vsLspTagHelperTooltipFactory);
var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.DirectiveAttribute); var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.DirectiveAttribute);
razorCompletionItem.SetAttributeCompletionDescription(_attributeDescription); razorCompletionItem.SetAttributeCompletionDescription(_attributeDescription);
var completionList = CreateLSPCompletionList(new[] { razorCompletionItem }); var completionList = CreateLSPCompletionList(razorCompletionItem);
var completionItem = completionList.Items.Single() as VSInternalCompletionItem; var completionItem = completionList.Items.Single() as VSInternalCompletionItem;
// Act // Act
@ -124,7 +124,7 @@ public class RazorCompletionItemResolverTest : LanguageServerTestBase
var resolver = new RazorCompletionItemResolver(_lspTagHelperTooltipFactory, _vsLspTagHelperTooltipFactory); var resolver = new RazorCompletionItemResolver(_lspTagHelperTooltipFactory, _vsLspTagHelperTooltipFactory);
var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.DirectiveAttributeParameter); var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.DirectiveAttributeParameter);
razorCompletionItem.SetAttributeCompletionDescription(_attributeDescription); razorCompletionItem.SetAttributeCompletionDescription(_attributeDescription);
var completionList = CreateLSPCompletionList(new[] { razorCompletionItem }); var completionList = CreateLSPCompletionList(razorCompletionItem);
var completionItem = completionList.Items.Single() as VSInternalCompletionItem; var completionItem = completionList.Items.Single() as VSInternalCompletionItem;
// Act // Act
@ -142,7 +142,7 @@ public class RazorCompletionItemResolverTest : LanguageServerTestBase
var resolver = new RazorCompletionItemResolver(_lspTagHelperTooltipFactory, _vsLspTagHelperTooltipFactory); var resolver = new RazorCompletionItemResolver(_lspTagHelperTooltipFactory, _vsLspTagHelperTooltipFactory);
var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.TagHelperElement); var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.TagHelperElement);
razorCompletionItem.SetTagHelperElementDescriptionInfo(_elementDescription); razorCompletionItem.SetTagHelperElementDescriptionInfo(_elementDescription);
var completionList = CreateLSPCompletionList(new[] { razorCompletionItem }); var completionList = CreateLSPCompletionList(razorCompletionItem);
var completionItem = completionList.Items.Single() as VSInternalCompletionItem; var completionItem = completionList.Items.Single() as VSInternalCompletionItem;
// Act // Act
@ -160,7 +160,7 @@ public class RazorCompletionItemResolverTest : LanguageServerTestBase
var resolver = new RazorCompletionItemResolver(_lspTagHelperTooltipFactory, _vsLspTagHelperTooltipFactory); var resolver = new RazorCompletionItemResolver(_lspTagHelperTooltipFactory, _vsLspTagHelperTooltipFactory);
var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.TagHelperAttribute); var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.TagHelperAttribute);
razorCompletionItem.SetAttributeCompletionDescription(_attributeDescription); razorCompletionItem.SetAttributeCompletionDescription(_attributeDescription);
var completionList = CreateLSPCompletionList(new[] { razorCompletionItem }); var completionList = CreateLSPCompletionList(razorCompletionItem);
var completionItem = completionList.Items.Single() as VSInternalCompletionItem; var completionItem = completionList.Items.Single() as VSInternalCompletionItem;
// Act // Act
@ -178,7 +178,7 @@ public class RazorCompletionItemResolverTest : LanguageServerTestBase
var resolver = new RazorCompletionItemResolver(_lspTagHelperTooltipFactory, _vsLspTagHelperTooltipFactory); var resolver = new RazorCompletionItemResolver(_lspTagHelperTooltipFactory, _vsLspTagHelperTooltipFactory);
var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.DirectiveAttribute); var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.DirectiveAttribute);
razorCompletionItem.SetAttributeCompletionDescription(_attributeDescription); razorCompletionItem.SetAttributeCompletionDescription(_attributeDescription);
var completionList = CreateLSPCompletionList(new[] { razorCompletionItem }); var completionList = CreateLSPCompletionList(razorCompletionItem);
var completionItem = completionList.Items.Single() as VSInternalCompletionItem; var completionItem = completionList.Items.Single() as VSInternalCompletionItem;
// Act // Act
@ -196,7 +196,7 @@ public class RazorCompletionItemResolverTest : LanguageServerTestBase
var resolver = new RazorCompletionItemResolver(_lspTagHelperTooltipFactory, _vsLspTagHelperTooltipFactory); var resolver = new RazorCompletionItemResolver(_lspTagHelperTooltipFactory, _vsLspTagHelperTooltipFactory);
var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.DirectiveAttributeParameter); var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.DirectiveAttributeParameter);
razorCompletionItem.SetAttributeCompletionDescription(_attributeDescription); razorCompletionItem.SetAttributeCompletionDescription(_attributeDescription);
var completionList = CreateLSPCompletionList(new[] { razorCompletionItem }); var completionList = CreateLSPCompletionList(razorCompletionItem);
var completionItem = completionList.Items.Single() as VSInternalCompletionItem; var completionItem = completionList.Items.Single() as VSInternalCompletionItem;
// Act // Act
@ -214,7 +214,7 @@ public class RazorCompletionItemResolverTest : LanguageServerTestBase
var resolver = new RazorCompletionItemResolver(_lspTagHelperTooltipFactory, _vsLspTagHelperTooltipFactory); var resolver = new RazorCompletionItemResolver(_lspTagHelperTooltipFactory, _vsLspTagHelperTooltipFactory);
var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.TagHelperElement); var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.TagHelperElement);
razorCompletionItem.SetTagHelperElementDescriptionInfo(_elementDescription); razorCompletionItem.SetTagHelperElementDescriptionInfo(_elementDescription);
var completionList = CreateLSPCompletionList(new[] { razorCompletionItem }); var completionList = CreateLSPCompletionList(razorCompletionItem);
var completionItem = completionList.Items.Single() as VSInternalCompletionItem; var completionItem = completionList.Items.Single() as VSInternalCompletionItem;
// Act // Act
@ -232,7 +232,7 @@ public class RazorCompletionItemResolverTest : LanguageServerTestBase
var resolver = new RazorCompletionItemResolver(_lspTagHelperTooltipFactory, _vsLspTagHelperTooltipFactory); var resolver = new RazorCompletionItemResolver(_lspTagHelperTooltipFactory, _vsLspTagHelperTooltipFactory);
var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.TagHelperAttribute); var razorCompletionItem = new RazorCompletionItem("TestItem", "TestItem", RazorCompletionItemKind.TagHelperAttribute);
razorCompletionItem.SetAttributeCompletionDescription(_attributeDescription); razorCompletionItem.SetAttributeCompletionDescription(_attributeDescription);
var completionList = CreateLSPCompletionList(new[] { razorCompletionItem }); var completionList = CreateLSPCompletionList(razorCompletionItem);
var completionItem = completionList.Items.Single() as VSInternalCompletionItem; var completionItem = completionList.Items.Single() as VSInternalCompletionItem;
// Act // Act
@ -259,9 +259,6 @@ public class RazorCompletionItemResolverTest : LanguageServerTestBase
Assert.Null(resolvedCompletionItem); Assert.Null(resolvedCompletionItem);
} }
private VSInternalCompletionList CreateLSPCompletionList(IReadOnlyList<RazorCompletionItem> razorCompletionItems) private VSInternalCompletionList CreateLSPCompletionList(params RazorCompletionItem[] razorCompletionItems)
{ => RazorCompletionListProvider.CreateLSPCompletionList(razorCompletionItems.ToImmutableArray(), _defaultClientCapability);
var completionList = RazorCompletionListProvider.CreateLSPCompletionList(razorCompletionItems, _defaultClientCapability);
return completionList;
}
} }

Просмотреть файл

@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion;
public class RazorCompletionListProvierTest : LanguageServerTestBase public class RazorCompletionListProvierTest : LanguageServerTestBase
{ {
private readonly RazorCompletionFactsService _completionFactsService; private readonly IRazorCompletionFactsService _completionFactsService;
private readonly CompletionListCache _completionListCache; private readonly CompletionListCache _completionListCache;
private readonly VSInternalClientCapabilities _clientCapabilities; private readonly VSInternalClientCapabilities _clientCapabilities;
private readonly VSInternalCompletionContext _defaultCompletionContext; private readonly VSInternalCompletionContext _defaultCompletionContext;
@ -35,7 +35,7 @@ public class RazorCompletionListProvierTest : LanguageServerTestBase
public RazorCompletionListProvierTest(ITestOutputHelper testOutput) public RazorCompletionListProvierTest(ITestOutputHelper testOutput)
: base(testOutput) : base(testOutput)
{ {
_completionFactsService = new DefaultRazorCompletionFactsService(GetCompletionProviders()); _completionFactsService = new RazorCompletionFactsService(GetCompletionProviders());
_completionListCache = new CompletionListCache(); _completionListCache = new CompletionListCache();
_clientCapabilities = new VSInternalClientCapabilities() _clientCapabilities = new VSInternalClientCapabilities()
{ {
@ -59,7 +59,7 @@ public class RazorCompletionListProvierTest : LanguageServerTestBase
_defaultCompletionContext = new VSInternalCompletionContext(); _defaultCompletionContext = new VSInternalCompletionContext();
} }
private static IEnumerable<RazorCompletionItemProvider> GetCompletionProviders(IOptionsMonitor<RazorLSPOptions> optionsMonitor = null) private static IEnumerable<IRazorCompletionItemProvider> GetCompletionProviders(IOptionsMonitor<RazorLSPOptions> optionsMonitor = null)
{ {
// Working around strong naming restriction. // Working around strong naming restriction.
var tagHelperFactsService = new DefaultTagHelperFactsService(); var tagHelperFactsService = new DefaultTagHelperFactsService();
@ -67,7 +67,7 @@ public class RazorCompletionListProvierTest : LanguageServerTestBase
optionsMonitor ??= TestRazorLSPOptionsMonitor.Create(); optionsMonitor ??= TestRazorLSPOptionsMonitor.Create();
var completionProviders = new RazorCompletionItemProvider[] var completionProviders = new IRazorCompletionItemProvider[]
{ {
new DirectiveCompletionItemProvider(), new DirectiveCompletionItemProvider(),
new DirectiveAttributeCompletionItemProvider(tagHelperFactsService), new DirectiveAttributeCompletionItemProvider(tagHelperFactsService),
@ -582,7 +582,7 @@ public class RazorCompletionListProvierTest : LanguageServerTestBase
var optionsMonitor = TestRazorLSPOptionsMonitor.Create(); var optionsMonitor = TestRazorLSPOptionsMonitor.Create();
await optionsMonitor.UpdateAsync(optionsMonitor.CurrentValue with { AutoInsertAttributeQuotes = false }, DisposalToken); await optionsMonitor.UpdateAsync(optionsMonitor.CurrentValue with { AutoInsertAttributeQuotes = false }, DisposalToken);
var completionFactsService = new DefaultRazorCompletionFactsService(GetCompletionProviders(optionsMonitor)); var completionFactsService = new RazorCompletionFactsService(GetCompletionProviders(optionsMonitor));
var provider = new RazorCompletionListProvider(completionFactsService, _completionListCache, LoggerFactory); var provider = new RazorCompletionListProvider(completionFactsService, _completionListCache, LoggerFactory);
// Act // Act

Просмотреть файл

@ -3,6 +3,7 @@
#nullable disable #nullable disable
using System.Collections.Immutable;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common;
@ -12,13 +13,8 @@ using Xunit.Abstractions;
namespace Microsoft.CodeAnalysis.Razor.Completion; namespace Microsoft.CodeAnalysis.Razor.Completion;
public class DefaultRazorCompletionFactsServiceTest : TestBase public class DefaultRazorCompletionFactsServiceTest(ITestOutputHelper testOutput) : TestBase(testOutput)
{ {
public DefaultRazorCompletionFactsServiceTest(ITestOutputHelper testOutput)
: base(testOutput)
{
}
[Fact] [Fact]
public void GetDirectiveCompletionItems_AllProvidersCompletionItems() public void GetDirectiveCompletionItems_AllProvidersCompletionItems()
{ {
@ -27,10 +23,10 @@ public class DefaultRazorCompletionFactsServiceTest : TestBase
var tagHelperDocumentContext = TagHelperDocumentContext.Create(prefix: null, Enumerable.Empty<TagHelperDescriptor>()); var tagHelperDocumentContext = TagHelperDocumentContext.Create(prefix: null, Enumerable.Empty<TagHelperDescriptor>());
var completionItem1 = new RazorCompletionItem("displayText1", "insertText1", RazorCompletionItemKind.Directive); var completionItem1 = new RazorCompletionItem("displayText1", "insertText1", RazorCompletionItemKind.Directive);
var context = new RazorCompletionContext(0, null, syntaxTree, tagHelperDocumentContext); var context = new RazorCompletionContext(0, null, syntaxTree, tagHelperDocumentContext);
var provider1 = Mock.Of<RazorCompletionItemProvider>(p => p.GetCompletionItems(context) == new[] { completionItem1 }, MockBehavior.Strict); var provider1 = Mock.Of<IRazorCompletionItemProvider>(p => p.GetCompletionItems(context) == ImmutableArray.Create(completionItem1), MockBehavior.Strict);
var completionItem2 = new RazorCompletionItem("displayText2", "insertText2", RazorCompletionItemKind.Directive); var completionItem2 = new RazorCompletionItem("displayText2", "insertText2", RazorCompletionItemKind.Directive);
var provider2 = Mock.Of<RazorCompletionItemProvider>(p => p.GetCompletionItems(context) == new[] { completionItem2 }, MockBehavior.Strict); var provider2 = Mock.Of<IRazorCompletionItemProvider>(p => p.GetCompletionItems(context) == ImmutableArray.Create(completionItem2), MockBehavior.Strict);
var completionFactsService = new DefaultRazorCompletionFactsService(new[] { provider1, provider2 }); var completionFactsService = new RazorCompletionFactsService(new[] { provider1, provider2 });
// Act // Act
var completionItems = completionFactsService.GetCompletionItems(context); var completionItems = completionFactsService.GetCompletionItems(context);

Просмотреть файл

@ -93,7 +93,7 @@ public class DirectiveAttributeParameterCompletionItemProviderTest : RazorIntegr
var completions = _provider.GetCompletionItems(context); var completions = _provider.GetCompletionItems(context);
// Assert // Assert
Assert.Equal(6, completions.Count); Assert.Equal(6, completions.Length);
AssertContains(completions, "culture"); AssertContains(completions, "culture");
AssertContains(completions, "event"); AssertContains(completions, "event");
AssertContains(completions, "format"); AssertContains(completions, "format");

Просмотреть файл

@ -23,7 +23,7 @@ public class DefaultVisualStudioDescriptionFactoryTest : TestBase
public void CreateClassifiedDescription_SingleDescription_NoSeparator() public void CreateClassifiedDescription_SingleDescription_NoSeparator()
{ {
// Arrange // Arrange
var factory = new DefaultVisualStudioDescriptionFactory(); var factory = new VisualStudioDescriptionFactory();
var description = new AggregateBoundAttributeDescription(new[] var description = new AggregateBoundAttributeDescription(new[]
{ {
new BoundAttributeDescriptionInfo("TheReturnType", "TheTypeName", "ThePropertyName", "The documentation"), new BoundAttributeDescriptionInfo("TheReturnType", "TheTypeName", "ThePropertyName", "The documentation"),
@ -33,14 +33,14 @@ public class DefaultVisualStudioDescriptionFactoryTest : TestBase
var result = factory.CreateClassifiedDescription(description); var result = factory.CreateClassifiedDescription(description);
// Assert // Assert
Assert.DoesNotContain(DefaultVisualStudioDescriptionFactory.SeparatorElement, result.Elements); Assert.DoesNotContain(VisualStudioDescriptionFactory.SeparatorElement, result.Elements);
} }
[Fact] [Fact]
public void CreateClassifiedDescription_MultipleDescription_Separator() public void CreateClassifiedDescription_MultipleDescription_Separator()
{ {
// Arrange // Arrange
var factory = new DefaultVisualStudioDescriptionFactory(); var factory = new VisualStudioDescriptionFactory();
var description = new AggregateBoundAttributeDescription(new[] var description = new AggregateBoundAttributeDescription(new[]
{ {
new BoundAttributeDescriptionInfo("TheReturnType", "TheTypeName", "ThePropertyName", "The documentation"), new BoundAttributeDescriptionInfo("TheReturnType", "TheTypeName", "ThePropertyName", "The documentation"),
@ -51,14 +51,14 @@ public class DefaultVisualStudioDescriptionFactoryTest : TestBase
var result = factory.CreateClassifiedDescription(description); var result = factory.CreateClassifiedDescription(description);
// Assert // Assert
Assert.Contains(DefaultVisualStudioDescriptionFactory.SeparatorElement, result.Elements); Assert.Contains(VisualStudioDescriptionFactory.SeparatorElement, result.Elements);
} }
[Fact] [Fact]
public void CreateClassifiedDescription_RepresentsReturnType() public void CreateClassifiedDescription_RepresentsReturnType()
{ {
// Arrange // Arrange
var factory = new DefaultVisualStudioDescriptionFactory(); var factory = new VisualStudioDescriptionFactory();
var description = new AggregateBoundAttributeDescription(new[] var description = new AggregateBoundAttributeDescription(new[]
{ {
new BoundAttributeDescriptionInfo("TheReturnType", "TheTypeName", "ThePropertyName", "The documentation"), new BoundAttributeDescriptionInfo("TheReturnType", "TheTypeName", "ThePropertyName", "The documentation"),
@ -76,7 +76,7 @@ public class DefaultVisualStudioDescriptionFactoryTest : TestBase
public void CreateClassifiedDescription_RepresentsTypeName() public void CreateClassifiedDescription_RepresentsTypeName()
{ {
// Arrange // Arrange
var factory = new DefaultVisualStudioDescriptionFactory(); var factory = new VisualStudioDescriptionFactory();
var description = new AggregateBoundAttributeDescription(new[] var description = new AggregateBoundAttributeDescription(new[]
{ {
new BoundAttributeDescriptionInfo("TheReturnType", "TheTypeName", "ThePropertyName", "The documentation"), new BoundAttributeDescriptionInfo("TheReturnType", "TheTypeName", "ThePropertyName", "The documentation"),
@ -94,7 +94,7 @@ public class DefaultVisualStudioDescriptionFactoryTest : TestBase
public void CreateClassifiedDescription_RepresentsPropertyName() public void CreateClassifiedDescription_RepresentsPropertyName()
{ {
// Arrange // Arrange
var factory = new DefaultVisualStudioDescriptionFactory(); var factory = new VisualStudioDescriptionFactory();
var description = new AggregateBoundAttributeDescription(new[] var description = new AggregateBoundAttributeDescription(new[]
{ {
new BoundAttributeDescriptionInfo("TheReturnType", "TheTypeName", "ThePropertyName", "The documentation"), new BoundAttributeDescriptionInfo("TheReturnType", "TheTypeName", "ThePropertyName", "The documentation"),
@ -112,7 +112,7 @@ public class DefaultVisualStudioDescriptionFactoryTest : TestBase
public void CreateClassifiedDescription_RepresentsDocumentation() public void CreateClassifiedDescription_RepresentsDocumentation()
{ {
// Arrange // Arrange
var factory = new DefaultVisualStudioDescriptionFactory(); var factory = new VisualStudioDescriptionFactory();
var description = new AggregateBoundAttributeDescription(new[] var description = new AggregateBoundAttributeDescription(new[]
{ {
new BoundAttributeDescriptionInfo("TheReturnType", "TheTypeName", "ThePropertyName", "The documentation"), new BoundAttributeDescriptionInfo("TheReturnType", "TheTypeName", "ThePropertyName", "The documentation"),
@ -130,7 +130,7 @@ public class DefaultVisualStudioDescriptionFactoryTest : TestBase
public void CreateClassifiedDescription_CanSimplifyKeywordReturnTypes() public void CreateClassifiedDescription_CanSimplifyKeywordReturnTypes()
{ {
// Arrange // Arrange
var factory = new DefaultVisualStudioDescriptionFactory(); var factory = new VisualStudioDescriptionFactory();
var description = new AggregateBoundAttributeDescription(new[] var description = new AggregateBoundAttributeDescription(new[]
{ {
new BoundAttributeDescriptionInfo("System.String", "TheTypeName", "ThePropertyName", "The documentation"), new BoundAttributeDescriptionInfo("System.String", "TheTypeName", "ThePropertyName", "The documentation"),
@ -149,7 +149,7 @@ public class DefaultVisualStudioDescriptionFactoryTest : TestBase
public void CreateClassifiedDescription_CanRepresentMultipleDescriptions() public void CreateClassifiedDescription_CanRepresentMultipleDescriptions()
{ {
// Arrange // Arrange
var factory = new DefaultVisualStudioDescriptionFactory(); var factory = new VisualStudioDescriptionFactory();
var description = new AggregateBoundAttributeDescription(new[] var description = new AggregateBoundAttributeDescription(new[]
{ {
new BoundAttributeDescriptionInfo("System.String", "TheTypeName", "ThePropertyName", "The documentation"), new BoundAttributeDescriptionInfo("System.String", "TheTypeName", "ThePropertyName", "The documentation"),

Просмотреть файл

@ -46,11 +46,11 @@ public class RazorDirectiveAttributeCompletionSourceTest : ProjectSnapshotManage
// Arrange // Arrange
var expectedResult = new ContainerElement(ContainerElementStyle.Wrapped); var expectedResult = new ContainerElement(ContainerElementStyle.Wrapped);
var description = new AggregateBoundAttributeDescription(Array.Empty<BoundAttributeDescriptionInfo>()); var description = new AggregateBoundAttributeDescription(Array.Empty<BoundAttributeDescriptionInfo>());
var descriptionFactory = Mock.Of<VisualStudioDescriptionFactory>(factory => factory.CreateClassifiedDescription(description) == expectedResult, MockBehavior.Strict); var descriptionFactory = Mock.Of<IVisualStudioDescriptionFactory>(factory => factory.CreateClassifiedDescription(description) == expectedResult, MockBehavior.Strict);
var source = new RazorDirectiveAttributeCompletionSource( var source = new RazorDirectiveAttributeCompletionSource(
Dispatcher, Dispatcher,
Mock.Of<VisualStudioRazorParser>(MockBehavior.Strict), Mock.Of<VisualStudioRazorParser>(MockBehavior.Strict),
Mock.Of<RazorCompletionFactsService>(MockBehavior.Strict), Mock.Of<IRazorCompletionFactsService>(MockBehavior.Strict),
Mock.Of<ICompletionBroker>(MockBehavior.Strict), Mock.Of<ICompletionBroker>(MockBehavior.Strict),
descriptionFactory, descriptionFactory,
JoinableTaskFactory); JoinableTaskFactory);
@ -240,9 +240,9 @@ public class RazorDirectiveAttributeCompletionSourceTest : ProjectSnapshotManage
var source = new RazorDirectiveAttributeCompletionSource( var source = new RazorDirectiveAttributeCompletionSource(
Dispatcher, Dispatcher,
Mock.Of<VisualStudioRazorParser>(MockBehavior.Strict), Mock.Of<VisualStudioRazorParser>(MockBehavior.Strict),
Mock.Of<RazorCompletionFactsService>(MockBehavior.Strict), Mock.Of<IRazorCompletionFactsService>(MockBehavior.Strict),
Mock.Of<ICompletionBroker>(MockBehavior.Strict), Mock.Of<ICompletionBroker>(MockBehavior.Strict),
Mock.Of<VisualStudioDescriptionFactory>(MockBehavior.Strict), Mock.Of<IVisualStudioDescriptionFactory>(MockBehavior.Strict),
JoinableTaskFactory); JoinableTaskFactory);
return source; return source;
} }

Просмотреть файл

@ -21,7 +21,7 @@ public class RazorDirectiveCompletionSourceProviderTest : ProjectSnapshotManager
{ {
private readonly IContentType _razorContentType; private readonly IContentType _razorContentType;
private readonly IContentType _nonRazorContentType; private readonly IContentType _nonRazorContentType;
private readonly RazorCompletionFactsService _completionFactsService; private readonly IRazorCompletionFactsService _completionFactsService;
public RazorDirectiveCompletionSourceProviderTest(ITestOutputHelper testOutput) public RazorDirectiveCompletionSourceProviderTest(ITestOutputHelper testOutput)
: base(testOutput) : base(testOutput)
@ -34,7 +34,7 @@ public class RazorDirectiveCompletionSourceProviderTest : ProjectSnapshotManager
c => c.IsOfType(It.IsAny<string>()) == false, c => c.IsOfType(It.IsAny<string>()) == false,
MockBehavior.Strict); MockBehavior.Strict);
_completionFactsService = Mock.Of<RazorCompletionFactsService>(MockBehavior.Strict); _completionFactsService = Mock.Of<IRazorCompletionFactsService>(MockBehavior.Strict);
} }
[Fact] [Fact]

Просмотреть файл

@ -33,12 +33,12 @@ public class RazorDirectiveCompletionSourceTest : ProjectSnapshotManagerDispatch
CSharpCodeParser.TagHelperPrefixDirectiveDescriptor, CSharpCodeParser.TagHelperPrefixDirectiveDescriptor,
}; };
private readonly RazorCompletionFactsService _completionFactsService; private readonly IRazorCompletionFactsService _completionFactsService;
public RazorDirectiveCompletionSourceTest(ITestOutputHelper testOutput) public RazorDirectiveCompletionSourceTest(ITestOutputHelper testOutput)
: base(testOutput) : base(testOutput)
{ {
_completionFactsService = new DefaultRazorCompletionFactsService(new[] { new DirectiveCompletionItemProvider() }); _completionFactsService = new RazorCompletionFactsService(new[] { new DirectiveCompletionItemProvider() });
} }
[UIFact] [UIFact]

Просмотреть файл

@ -0,0 +1,32 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Collections.Immutable;
using Microsoft.AspNetCore.Razor.PooledObjects;
namespace System.Collections.Generic;
internal static class EnumerableExtensions
{
public static ImmutableArray<TResult> SelectAsArray<T, TResult>(this IEnumerable<T> source, Func<T, TResult> selector)
{
if (source is IReadOnlyList<T> list)
{
return list.SelectAsArray(selector);
}
return BuildResult(source, selector);
static ImmutableArray<TResult> BuildResult(IEnumerable<T> items, Func<T, TResult> selector)
{
using var results = new PooledArrayBuilder<TResult>();
foreach (var item in items)
{
results.Add(selector(item));
}
return results.DrainToImmutable();
}
}
}

Просмотреть файл

@ -73,15 +73,14 @@ internal static class ImmutableArrayExtensions
static ImmutableArray<TResult> BuildResult(ImmutableArray<T> items, Func<T, TResult> selector) static ImmutableArray<TResult> BuildResult(ImmutableArray<T> items, Func<T, TResult> selector)
{ {
using var _ = ArrayBuilderPool<TResult>.GetPooledObject(out var result); using var results = new PooledArrayBuilder<TResult>(capacity: items.Length);
result.SetCapacityIfLarger(items.Length);
foreach (var item in items) foreach (var item in items)
{ {
result.Add(selector(item)); results.Add(selector(item));
} }
return result.DrainToImmutable(); return results.DrainToImmutable();
} }
} }
} }

Просмотреть файл

@ -67,6 +67,17 @@ internal ref struct PooledArrayBuilder<T>
_builder.Add(item); _builder.Add(item);
} }
public void AddRange(ImmutableArray<T> items)
{
if (items.Length == 0)
{
return;
}
_builder ??= GetBuilder();
_builder.AddRange(items);
}
public void AddRange(IReadOnlyList<T> items) public void AddRange(IReadOnlyList<T> items)
{ {
if (items.Count == 0) if (items.Count == 0)

Просмотреть файл

@ -0,0 +1,35 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Collections.Immutable;
using Microsoft.AspNetCore.Razor.PooledObjects;
namespace System.Collections.Generic;
internal static class ReadOnlyListExtensions
{
public static ImmutableArray<TResult> SelectAsArray<T, TResult>(this IReadOnlyList<T> source, Func<T, TResult> selector)
{
return source switch
{
[] => ImmutableArray<TResult>.Empty,
[var item] => ImmutableArray.Create(selector(item)),
[var item1, var item2] => ImmutableArray.Create(selector(item1), selector(item2)),
[var item1, var item2, var item3] => ImmutableArray.Create(selector(item1), selector(item2), selector(item3)),
[var item1, var item2, var item3, var item4] => ImmutableArray.Create(selector(item1), selector(item2), selector(item3), selector(item4)),
var items => BuildResult(items, selector)
};
static ImmutableArray<TResult> BuildResult(IReadOnlyList<T> items, Func<T, TResult> selector)
{
using var results = new PooledArrayBuilder<TResult>(capacity: items.Count);
for (var i = 0; i < items.Count; i++)
{
results.Add(selector(items[i]));
}
return results.DrainToImmutable();
}
}
}