|
// 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;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.EditorConfig.Parsing;
/// <summary>
/// Base representation of an editorconfig file that has been parsed
/// </summary>
/// <typeparam name="T">The kind of options that we expect to encounter in the editorconfig file.</typeparam>
/// <param name="FilePath">The full path to the editorconfig file on disk. Optional if not doing pathwise comparisons</param>
/// <param name="Options">The set of options that were discovered in the file.</param>
internal record class EditorConfigFile<T>(string? FilePath, ImmutableArray<T> Options)
where T : EditorConfigOption
{
private readonly Lazy<ImmutableArray<Section>> _sections = new(() => Options.SelectAsArray(x => x.Section).Distinct());
public ImmutableArray<Section> Sections => _sections.Value;
/// <summary>
/// Attempts to find a section of the editorconfig file that is an exact match for the given language.
/// </summary>
public bool TryGetSectionForLanguage(
Language language,
[NotNullWhen(true)] out Section? sectionResult)
=> TryGetSectionForLanguage(language, SectionMatch.ExactLanguageMatch, out sectionResult);
/// <summary>
/// Attempts to find a section of the editorconfig file that applies to the given language for the given criteria.
/// </summary>
public bool TryGetSectionForLanguage(
Language language,
SectionMatch matchKind,
[NotNullWhen(true)] out Section? sectionResult)
{
sectionResult = Sections
.Select(section => (matchKind: section.GetMatchKind(language), section))
.Where(tuple => tuple.matchKind.IsBetterOrEqualMatchThan(matchKind))
.OrderBy(x => x.matchKind)
.ThenByDescending(x => x.section.Span.Start)
.Select(x => x.section)
.FirstOrDefault();
return sectionResult is not null;
}
/// <summary>
/// Attempts to find a section of the editorconfig file that applies to the given file.
/// </summary>
public bool TryGetSectionForFilePath(
string filePath,
[NotNullWhen(true)] out Section? sectionResult)
{
if (FilePath is null)
{
throw new InvalidOperationException("No path was given for this editorconfig file");
}
return TryGetSectionForFilePath(filePath, SectionMatch.ExactLanguageMatch, out sectionResult);
}
/// <summary>
/// Attempts to find a section of the editorconfig file that applies to the given file for the given criteria.
/// </summary>
public bool TryGetSectionForFilePath(
string filePath,
SectionMatch matchKind,
[NotNullWhen(true)] out Section? sectionResult)
{
if (FilePath is null)
{
throw new InvalidOperationException("No path was given for this editorconfig file");
}
sectionResult = Sections
.SelectAsArray(section => (matchKind: section.GetMatchKind(filePath), section))
.WhereAsArray(tuple => tuple.matchKind.IsBetterOrEqualMatchThan(matchKind))
.OrderBy(x => x.matchKind) // Sort by best match kind
.ThenByDescending(x => x.section.Span.Start) // in event of a further tie, pick entry at the bottom of the file
.Select(x => x.section)
.FirstOrDefault();
return sectionResult is not null;
}
}
|