File: src\libraries\System.Private.CoreLib\src\System\CodeDom\Compiler\IndentedTextWriter.cs
Web Access
Project: src\src\coreclr\System.Private.CoreLib\System.Private.CoreLib.csproj (System.Private.CoreLib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
 
namespace System.CodeDom.Compiler
{
    public class IndentedTextWriter : TextWriter
    {
        private readonly TextWriter _writer;
        private readonly string _tabString;
        private int _indentLevel;
        private bool _tabsPending;
 
        public const string DefaultTabString = "    ";
 
        public IndentedTextWriter(TextWriter writer) : this(writer, DefaultTabString) { }
 
        public IndentedTextWriter(TextWriter writer, string tabString) : base(CultureInfo.InvariantCulture)
        {
            ArgumentNullException.ThrowIfNull(writer);
 
            _writer = writer;
            _tabString = tabString;
            _tabsPending = true;
        }
 
        public override Encoding Encoding => _writer.Encoding;
 
        [AllowNull]
        public override string NewLine
        {
            get { return _writer.NewLine; }
            set { _writer.NewLine = value; }
        }
 
        public int Indent
        {
            get { return _indentLevel; }
            set { _indentLevel = Math.Max(value, 0); }
        }
 
        public TextWriter InnerWriter => _writer;
 
        public override void Close() => _writer.Close();
 
        /// <inheritdoc/>
        public override ValueTask DisposeAsync() => _writer.DisposeAsync();
 
        public override void Flush() => _writer.Flush();
 
        /// <inheritdoc/>
        public override Task FlushAsync() => _writer.FlushAsync();
 
        /// <summary>
        /// Clears all buffers for this <see cref="IndentedTextWriter"/> asynchronously and causes any buffered data to be
        /// written to the underlying device.
        /// </summary>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous flush operation.</returns>
        public override Task FlushAsync(CancellationToken cancellationToken) =>
            cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) :
            GetType() != typeof(IndentedTextWriter) ? FlushAsync() :
            _writer.FlushAsync(cancellationToken);
 
        protected virtual void OutputTabs()
        {
            if (_tabsPending)
            {
                for (int i = 0; i < _indentLevel; i++)
                {
                    _writer.Write(_tabString);
                }
                _tabsPending = false;
            }
        }
 
        /// <summary>
        /// Asynchronously outputs tabs to the underlying <see cref="TextWriter"/> based on the current <see cref="Indent"/>.
        /// </summary>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        protected virtual async Task OutputTabsAsync()
        {
            if (_tabsPending)
            {
                for (int i = 0; i < _indentLevel; i++)
                {
                    await _writer.WriteAsync(_tabString).ConfigureAwait(false);
                }
                _tabsPending = false;
            }
        }
 
        public override void Write(string? s)
        {
            OutputTabs();
            _writer.Write(s);
        }
 
        public override void Write(bool value)
        {
            OutputTabs();
            _writer.Write(value);
        }
 
        public override void Write(char value)
        {
            OutputTabs();
            _writer.Write(value);
        }
 
        /// <summary>
        /// Writes out the specified <see cref="Rune"/>, inserting tabs at the start of every line.
        /// </summary>
        /// <param name="value">The <see cref="Rune"/> to write.</param>
        public override void Write(Rune value)
        {
            OutputTabs();
            _writer.Write(value);
        }
 
        public override void Write(char[]? buffer)
        {
            OutputTabs();
            _writer.Write(buffer);
        }
 
        public override void Write(char[] buffer, int index, int count)
        {
            OutputTabs();
            _writer.Write(buffer, index, count);
        }
 
        public override void Write(double value)
        {
            OutputTabs();
            _writer.Write(value);
        }
 
        public override void Write(float value)
        {
            OutputTabs();
            _writer.Write(value);
        }
 
        public override void Write(int value)
        {
            OutputTabs();
            _writer.Write(value);
        }
 
        public override void Write(long value)
        {
            OutputTabs();
            _writer.Write(value);
        }
 
        public override void Write(object? value)
        {
            OutputTabs();
            _writer.Write(value);
        }
 
        public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0)
        {
            OutputTabs();
            _writer.Write(format, arg0);
        }
 
        public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0, object? arg1)
        {
            OutputTabs();
            _writer.Write(format, arg0, arg1);
        }
 
        public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, params object?[] arg)
        {
            OutputTabs();
            _writer.Write(format, arg);
        }
 
        /// <summary>
        /// Writes out a formatted string, using the same semantics as specified.
        /// </summary>
        /// <param name="format">The formatting string to use.</param>
        /// <param name="arg">The argument span to output.</param>
        public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, params ReadOnlySpan<object?> arg)
        {
            OutputTabs();
            _writer.Write(format, arg);
        }
 
        /// <summary>
        /// Asynchronously writes the specified <see cref="char"/> to the underlying <see cref="TextWriter"/>, inserting
        /// tabs at the start of every line.
        /// </summary>
        /// <param name="value">The <see cref="char"/> to write.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public override async Task WriteAsync(char value)
        {
            await OutputTabsAsync().ConfigureAwait(false);
            await _writer.WriteAsync(value).ConfigureAwait(false);
        }
 
        /// <summary>
        /// Asynchronously writes the specified <see cref="Rune"/> to the underlying <see cref="TextWriter"/>, inserting
        /// tabs at the start of every line.
        /// </summary>
        /// <param name="value">The <see cref="Rune"/> to write.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public override async Task WriteAsync(Rune value)
        {
            await OutputTabsAsync().ConfigureAwait(false);
            await _writer.WriteAsync(value).ConfigureAwait(false);
        }
 
        /// <summary>
        /// Asynchronously writes the specified number of <see cref="char"/>s from the specified buffer
        /// to the underlying <see cref="TextWriter"/>, starting at the specified index, and outputting tabs at the
        /// start of every new line.
        /// </summary>
        /// <param name="buffer">The array to write from.</param>
        /// <param name="index">Index in the array to stort writing at.</param>
        /// <param name="count">The number of characters to write.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public override async Task WriteAsync(char[] buffer, int index, int count)
        {
            await OutputTabsAsync().ConfigureAwait(false);
            await _writer.WriteAsync(buffer, index, count).ConfigureAwait(false);
        }
 
        /// <summary>
        /// Asynchronously writes the specified string to the underlying <see cref="TextWriter"/>, inserting tabs at the
        /// start of every line.
        /// </summary>
        /// <param name="value">The string to write.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public override async Task WriteAsync(string? value)
        {
            await OutputTabsAsync().ConfigureAwait(false);
            await _writer.WriteAsync(value).ConfigureAwait(false);
        }
 
        /// <summary>
        /// Asynchronously writes the specified characters to the underlying <see cref="TextWriter"/>, inserting tabs at the
        /// start of every line.
        /// </summary>
        /// <param name="buffer">The characters to write.</param>
        /// <param name="cancellationToken">Token for canceling the operation.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public override async Task WriteAsync(ReadOnlyMemory<char> buffer, CancellationToken cancellationToken = default)
        {
            await OutputTabsAsync().ConfigureAwait(false);
            await _writer.WriteAsync(buffer, cancellationToken).ConfigureAwait(false);
        }
 
        /// <summary>
        /// Asynchronously writes the contents of the specified <see cref="StringBuilder"/> to the underlying <see cref="TextWriter"/>, inserting tabs at the
        /// start of every line.
        /// </summary>
        /// <param name="value">The text to write.</param>
        /// <param name="cancellationToken">Token for canceling the operation.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public override async Task WriteAsync(StringBuilder? value, CancellationToken cancellationToken = default)
        {
            await OutputTabsAsync().ConfigureAwait(false);
            await _writer.WriteAsync(value, cancellationToken).ConfigureAwait(false);
        }
 
        public void WriteLineNoTabs(string? s)
        {
            _writer.WriteLine(s);
        }
 
        /// <summary>
        /// Asynchronously writes the specified string to the underlying <see cref="TextWriter"/> without inserting tabs.
        /// </summary>
        /// <param name="s">The string to write.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public Task WriteLineNoTabsAsync(string? s)
        {
            return _writer.WriteLineAsync(s);
        }
 
        public override void WriteLine(string? s)
        {
            OutputTabs();
            _writer.WriteLine(s);
            _tabsPending = true;
        }
 
        public override void WriteLine()
        {
            OutputTabs();
            _writer.WriteLine();
            _tabsPending = true;
        }
 
        public override void WriteLine(bool value)
        {
            OutputTabs();
            _writer.WriteLine(value);
            _tabsPending = true;
        }
 
        public override void WriteLine(char value)
        {
            OutputTabs();
            _writer.WriteLine(value);
            _tabsPending = true;
        }
 
        /// <summary>
        /// Writes out the specified <see cref="Rune"/>, followed by a line terminator, inserting tabs at the start of every line.
        /// </summary>
        /// <param name="value">The <see cref="Rune"/> to write.</param>
        public override void WriteLine(Rune value)
        {
            OutputTabs();
            _writer.WriteLine(value);
            _tabsPending = true;
        }
 
        public override void WriteLine(char[]? buffer)
        {
            OutputTabs();
            _writer.WriteLine(buffer);
            _tabsPending = true;
        }
 
        public override void WriteLine(char[] buffer, int index, int count)
        {
            OutputTabs();
            _writer.WriteLine(buffer, index, count);
            _tabsPending = true;
        }
 
        public override void WriteLine(double value)
        {
            OutputTabs();
            _writer.WriteLine(value);
            _tabsPending = true;
        }
 
        public override void WriteLine(float value)
        {
            OutputTabs();
            _writer.WriteLine(value);
            _tabsPending = true;
        }
 
        public override void WriteLine(int value)
        {
            OutputTabs();
            _writer.WriteLine(value);
            _tabsPending = true;
        }
 
        public override void WriteLine(long value)
        {
            OutputTabs();
            _writer.WriteLine(value);
            _tabsPending = true;
        }
 
        public override void WriteLine(object? value)
        {
            OutputTabs();
            _writer.WriteLine(value);
            _tabsPending = true;
        }
 
        public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0)
        {
            OutputTabs();
            _writer.WriteLine(format, arg0);
            _tabsPending = true;
        }
 
        public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, object? arg0, object? arg1)
        {
            OutputTabs();
            _writer.WriteLine(format, arg0, arg1);
            _tabsPending = true;
        }
 
        public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, params object?[] arg)
        {
            OutputTabs();
            _writer.WriteLine(format, arg);
            _tabsPending = true;
        }
 
        /// <summary>
        /// Writes out a formatted string, followed by a line terminator, using the same semantics as specified.
        /// </summary>
        /// <param name="format">The formatting string to use.</param>
        /// <param name="arg">The argument span to output.</param>
        public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format, params ReadOnlySpan<object?> arg)
        {
            OutputTabs();
            _writer.WriteLine(format, arg);
            _tabsPending = true;
        }
 
        [CLSCompliant(false)]
        public override void WriteLine(uint value)
        {
            OutputTabs();
            _writer.WriteLine(value);
            _tabsPending = true;
        }
 
        /// <inheritdoc/>
        public override async Task WriteLineAsync()
        {
            await OutputTabsAsync().ConfigureAwait(false);
            await _writer.WriteLineAsync().ConfigureAwait(false);
            _tabsPending = true;
        }
 
        /// <summary>
        /// Asynchronously writes the specified <see cref="char"/> to the underlying <see cref="TextWriter"/> followed by a line terminator, inserting tabs
        /// at the start of every line.
        /// </summary>
        /// <param name="value">The character to write.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public override async Task WriteLineAsync(char value)
        {
            await OutputTabsAsync().ConfigureAwait(false);
            await _writer.WriteLineAsync(value).ConfigureAwait(false);
            _tabsPending = true;
        }
 
        /// <summary>
        /// Asynchronously writes the specified <see cref="Rune"/> to the underlying <see cref="TextWriter"/> followed by a line terminator, inserting tabs
        /// at the start of every line.
        /// </summary>
        /// <param name="value">The character to write.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public override async Task WriteLineAsync(Rune value)
        {
            await OutputTabsAsync().ConfigureAwait(false);
            await _writer.WriteLineAsync(value).ConfigureAwait(false);
            _tabsPending = true;
        }
 
        /// <summary>
        /// Asynchronously writes the specified number of characters from the specified buffer followed by a line terminator,
        /// to the underlying <see cref="TextWriter"/>, starting at the specified index within the buffer, inserting tabs at the start of every line.
        /// </summary>
        /// <param name="buffer">The buffer containing characters to write.</param>
        /// <param name="index">The index within the buffer to start writing at.</param>
        /// <param name="count">The number of characters to write.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public override async Task WriteLineAsync(char[] buffer, int index, int count)
        {
            await OutputTabsAsync().ConfigureAwait(false);
            await _writer.WriteLineAsync(buffer, index, count).ConfigureAwait(false);
            _tabsPending = true;
        }
 
        /// <summary>
        /// Asynchronously writes the specified string followed by a line terminator to the underlying <see cref="TextWriter"/>, inserting
        /// tabs at the start of every line.
        /// </summary>
        /// <param name="value">The string to write.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public override async Task WriteLineAsync(string? value)
        {
            await OutputTabsAsync().ConfigureAwait(false);
            await _writer.WriteLineAsync(value).ConfigureAwait(false);
            _tabsPending = true;
        }
 
        /// <summary>
        /// Asynchronously writes the specified characters followed by a line terminator to the underlying <see cref="TextWriter"/>, inserting
        /// tabs at the start of every line.
        /// </summary>
        /// <param name="buffer">The characters to write.</param>
        /// <param name="cancellationToken">Token for canceling the operation.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public override async Task WriteLineAsync(ReadOnlyMemory<char> buffer, CancellationToken cancellationToken = default)
        {
            await OutputTabsAsync().ConfigureAwait(false);
            await _writer.WriteLineAsync(buffer, cancellationToken).ConfigureAwait(false);
            _tabsPending = true;
        }
 
        /// <summary>
        /// Asynchronously writes the contents of the specified <see cref="StringBuilder"/> followed by a line terminator to the
        /// underlying <see cref="TextWriter"/>, inserting tabs at the start of every line.
        /// </summary>
        /// <param name="value">The text to write.</param>
        /// <param name="cancellationToken">Token for canceling the operation.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public override async Task WriteLineAsync(StringBuilder? value, CancellationToken cancellationToken = default)
        {
            await OutputTabsAsync().ConfigureAwait(false);
            await _writer.WriteLineAsync(value, cancellationToken).ConfigureAwait(false);
            _tabsPending = true;
        }
    }
}