|
// 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 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);
}
}
}
|