File: Features\UnifiedSuggestions\UnifiedSuggestedActionSetComparer.cs
Web Access
Project: src\src\LanguageServer\Protocol\Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj (Microsoft.CodeAnalysis.LanguageServer.Protocol)
// 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.
 
#nullable disable
 
using System;
using System.Collections.Generic;
using Microsoft.CodeAnalysis.Text;
 
namespace Microsoft.CodeAnalysis.UnifiedSuggestions;
 
internal sealed class UnifiedSuggestedActionSetComparer : IComparer<UnifiedSuggestedActionSet>
{
    private readonly TextSpan? _targetSpan;
 
    public UnifiedSuggestedActionSetComparer(TextSpan? targetSpan)
        => _targetSpan = targetSpan;
 
    private static int Distance(TextSpan? maybeA, TextSpan? maybeB)
    {
        // If we don't have a text span or target point we cannot calculate the distance between them
        if (!maybeA.HasValue || !maybeB.HasValue)
        {
            return int.MaxValue;
        }
 
        var a = maybeA.Value;
        var b = maybeB.Value;
 
        // The distance of two spans is symetric sumation of:
        // - the distance of a's start to b's start
        // - the distance of a's end to b's end
        //
        // This particular metric has been chosen because it is both simple
        // and uses the all the information in both spans. A weighting (i.e.
        // the distance of starts is more important) could be added but it
        // didn't seem necessary.
        //
        // E.g.: for spans [ ] and $ $ the distance is distanceOfStarts+distanceOfEnds:
        // $ $ [  ] has distance 2+3
        // $ [   ]$ has distance 1+0
        // $[    ]$ has distance 0+0
        // $ []   $ has distance 1+3
        // $[]    $ has distance 0+4
        var startsDistance = Math.Abs(a.Start - b.Start);
        var endsDistance = Math.Abs(a.End - b.End);
 
        return startsDistance + endsDistance;
    }
 
    public int Compare(UnifiedSuggestedActionSet x, UnifiedSuggestedActionSet y)
    {
        if (!_targetSpan.HasValue || !x.ApplicableToSpan.HasValue || !y.ApplicableToSpan.HasValue)
        {
            // Not enough data to compare, consider them equal
            return 0;
        }
 
        var distanceX = Distance(x.ApplicableToSpan, _targetSpan);
        var distanceY = Distance(y.ApplicableToSpan, _targetSpan);
 
        return distanceX.CompareTo(distanceY);
    }
}