File: Completion\Utilities.cs
Web Access
Project: src\src\Features\Core\Portable\Microsoft.CodeAnalysis.Features.csproj (Microsoft.CodeAnalysis.Features)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Collections.Immutable;
using Roslyn.Utilities;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Shared.Extensions;
 
namespace Microsoft.CodeAnalysis.Completion;
 
internal static class Utilities
{
    public static TextChange Collapse(SourceText newText, ImmutableArray<TextChange> changes)
    {
        if (changes.Length == 0)
        {
            return new TextChange(new TextSpan(0, 0), "");
        }
        else if (changes.Length == 1)
        {
            return changes[0];
        }
 
        // The span we want to replace goes from the start of the first span to the end of
        // the  last span.
        var totalOldSpan = TextSpan.FromBounds(changes.First().Span.Start, changes.Last().Span.End);
 
        // We figure out the text we're replacing with by actually just figuring out the
        // new span in the newText and grabbing the text out of that.  The newSpan will
        // start from the same position as the oldSpan, but it's length will be the old
        // span's length + all the deltas we accumulate through each text change.  i.e.
        // if the first change adds 2 characters and the second change adds 4, then 
        // the newSpan will be 2+4=6 characters longer than the old span.
        var sumOfDeltas = changes.Sum(c => c.NewText!.Length - c.Span.Length);
        var totalNewSpan = new TextSpan(totalOldSpan.Start, totalOldSpan.Length + sumOfDeltas);
 
        return new TextChange(totalOldSpan, newText.ToString(totalNewSpan));
    }
 
    // This is a temporarily method to support preference of IntelliCode items comparing to non-IntelliCode items.
    // We expect that Editor will introduce this support and we will get rid of relying on the "★" then.
    public static bool IsPreferredItem(this CompletionItem completionItem)
        => completionItem.DisplayText.StartsWith(UnicodeStarAndSpace);
 
    public const string UnicodeStarAndSpace = "\u2605 ";
 
    public static async Task<SyntaxContext> CreateSyntaxContextWithExistingSpeculativeModelAsync(Document document, int position, CancellationToken cancellationToken)
    {
        Contract.ThrowIfFalse(document.SupportsSemanticModel, "Should only be called from C#/VB providers.");
        var semanticModel = await document.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(false);
 
        var service = document.GetRequiredLanguageService<ISyntaxContextService>();
        return service.CreateContext(document, semanticModel, position, cancellationToken);
    }
}