File: Text\TextLineCollection.cs
Web Access
Project: src\src\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj (Microsoft.CodeAnalysis)
// 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;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
 
namespace Microsoft.CodeAnalysis.Text
{
    /// <summary>
    /// Abstract base class for <see cref="TextLine"/> collections.
    /// </summary>
    public abstract class TextLineCollection : IReadOnlyList<TextLine>
    {
        /// <summary>
        /// The count of <see cref="TextLine"/> items in the collection
        /// </summary>
        public abstract int Count { get; }
 
        /// <summary>
        /// Gets the <see cref="TextLine"/> item at the specified index.
        /// </summary>
        public abstract TextLine this[int index] { get; }
 
        /// <summary>
        /// The index of the TextLine that encompasses the character position.
        /// </summary>
        public abstract int IndexOf(int position);
 
        /// <summary>
        /// Gets a <see cref="TextLine"/> that encompasses the character position.
        /// </summary>
        /// <param name="position"></param>
        /// <returns></returns>
        public virtual TextLine GetLineFromPosition(int position)
        {
            return this[this.IndexOf(position)];
        }
 
        /// <summary>
        /// Gets a <see cref="LinePosition"/> corresponding to a character position.
        /// </summary>
        public virtual LinePosition GetLinePosition(int position)
        {
            var line = GetLineFromPosition(position);
            return new LinePosition(line.LineNumber, position - line.Start);
        }
 
        /// <summary>
        /// Convert a <see cref="TextSpan"/> to a <see cref="LinePositionSpan"/>.
        /// </summary>
        public LinePositionSpan GetLinePositionSpan(TextSpan span)
        {
            return new LinePositionSpan(GetLinePosition(span.Start), GetLinePosition(span.End));
        }
 
        /// <summary>
        /// Convert a <see cref="LinePosition"/> to a position.
        /// </summary>
        public int GetPosition(LinePosition position)
        {
            if (position.Line >= this.Count)
            {
                throw new ArgumentOutOfRangeException(nameof(position.Line), string.Format(CodeAnalysisResources.LineCannotBeGreaterThanEnd, position.Line, this.Count));
            }
 
            return this[position.Line].Start + position.Character;
        }
 
        /// <summary>
        /// Convert a <see cref="LinePositionSpan"/> to <see cref="TextSpan"/>.
        /// </summary>
        public TextSpan GetTextSpan(LinePositionSpan span)
        {
            return TextSpan.FromBounds(GetPosition(span.Start), GetPosition(span.End));
        }
 
        public Enumerator GetEnumerator()
        {
            return new Enumerator(this);
        }
 
        IEnumerator<TextLine> IEnumerable<TextLine>.GetEnumerator()
        {
            return this.GetEnumerator();
        }
 
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
 
        [SuppressMessage("Performance", "CA1067", Justification = "Equality not actually implemented")]
        public struct Enumerator : IEnumerator<TextLine>, IEnumerator
        {
            private readonly TextLineCollection _lines;
            private int _index;
 
            internal Enumerator(TextLineCollection lines, int index = -1)
            {
                _lines = lines;
                _index = index;
            }
 
            public TextLine Current
            {
                get
                {
                    var ndx = _index;
                    if (ndx >= 0 && ndx < _lines.Count)
                    {
                        return _lines[ndx];
                    }
                    else
                    {
                        return default(TextLine);
                    }
                }
            }
 
            public bool MoveNext()
            {
                if (_index < _lines.Count - 1)
                {
                    _index = _index + 1;
                    return true;
                }
 
                return false;
            }
 
            object IEnumerator.Current
            {
                get { return this.Current; }
            }
 
            bool IEnumerator.MoveNext()
            {
                return this.MoveNext();
            }
 
            void IEnumerator.Reset()
            {
            }
 
            void IDisposable.Dispose()
            {
            }
 
            public override bool Equals(object? obj)
            {
                throw new NotSupportedException();
            }
 
            public override int GetHashCode()
            {
                throw new NotSupportedException();
            }
        }
    }
}