File: Formatters\EndOfLineFormatter.cs
Web Access
Project: ..\..\..\src\BuiltInTools\dotnet-format\dotnet-format.csproj (dotnet-format)
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the MIT license.  See License.txt in the project root for license information.
 
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Text;
using Microsoft.Extensions.Logging;
 
namespace Microsoft.CodeAnalysis.Tools.Formatters
{
    internal sealed class EndOfLineFormatter : DocumentFormatter
    {
        protected override string FormatWarningDescription => Resources.Fix_end_of_line_marker;
 
        public override string Name => "ENDOFLINE";
        public override FixCategory Category => FixCategory.Whitespace;
 
        internal override Task<SourceText> FormatFileAsync(
            Document document,
            SourceText sourceText,
            OptionSet optionSet,
            AnalyzerConfigOptions analyzerConfigOptions,
            FormatOptions formatOptions,
            ILogger logger,
            CancellationToken cancellationToken)
        {
            return Task.Run(() =>
            {
                if (!TryGetEndOfLine(analyzerConfigOptions, out var endOfLine))
                {
                    return sourceText;
                }
 
                var newSourceText = sourceText;
                var changes = new List<TextChange>();
                for (var lineIndex = 0; lineIndex < newSourceText.Lines.Count; lineIndex++)
                {
                    var line = newSourceText.Lines[lineIndex];
                    var lineEndingSpan = new TextSpan(line.End, line.EndIncludingLineBreak - line.End);
 
                    // Check for end of file
                    if (lineEndingSpan.IsEmpty)
                    {
                        break;
                    }
 
                    var lineEnding = newSourceText.ToString(lineEndingSpan);
 
                    if (lineEnding == endOfLine)
                    {
                        continue;
                    }
 
                    changes.Add(new TextChange(lineEndingSpan, endOfLine));
                }
 
                newSourceText = newSourceText.WithChanges(changes);
 
                return newSourceText;
            });
        }
 
        public static bool TryGetEndOfLine(AnalyzerConfigOptions analyzerConfigOptions, [NotNullWhen(true)] out string? endOfLine)
        {
            if (analyzerConfigOptions != null &&
                analyzerConfigOptions.TryGetValue("end_of_line", out var endOfLineOption))
            {
                endOfLine = GetEndOfLine(endOfLineOption);
                return true;
            }
 
            endOfLine = null;
            return false;
        }
 
        private static string GetEndOfLine(string endOfLineOption)
        {
            return endOfLineOption switch
            {
                "lf" => "\n",
                "cr" => "\r",
                "crlf" => "\r\n",
                _ => Environment.NewLine,
            };
        }
 
        internal static string GetEndOfLineOption(string newLine)
        {
            return newLine switch
            {
                "\n" => "lf",
                "\r" => "cr",
                "\r\n" => "crlf",
                _ => GetEndOfLineOption(Environment.NewLine),
            };
        }
    }
}