[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/kidoz/dotpython/main/src/DotPython.Language/Text/SourceText.cs [Back]  [Original]

namespace DotPython.Language.Text;

public sealed class SourceText
{
    private readonly int[] _lineStarts;

    public SourceText(string text, string? filePath = null)
    {
        ArgumentNullException.ThrowIfNull(text);

        Content = text;
        FilePath = filePath;
        _lineStarts = FindLineStarts(text);
    }

    public string Content { get; }

    public string? FilePath { get; }

    public int Length => Content.Length;

    public int LineCount => _lineStarts.Length;

    public char this[int index] => Content[index];

    public string GetText(TextSpan span)
    {
        ValidateSpan(span);
        return Content.Substring(span.Start, span.Length);
    }

    public LinePosition GetLinePosition(int position)
    {
        ArgumentOutOfRangeException.ThrowIfNegative(position);
        ArgumentOutOfRangeException.ThrowIfGreaterThan(position, Length);

        var line = Array.BinarySearch(_lineStarts, position);
        if (line < 0)
        {
            line = ~line - 1;
        }

        return new LinePosition(line, position - _lineStarts[line]);
    }

    public TextSpan GetLineSpan(int line)
    {
        ArgumentOutOfRangeException.ThrowIfNegative(line);
        ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(line, LineCount);

        var start = _lineStarts[line];
        var end = line + 1 < LineCount ? _lineStarts[line + 1] : Length;
        return TextSpan.FromBounds(start, end);
    }

    private static int[] FindLineStarts(string text)
    {
        var starts = new List { 0 };

        for (var position = 0; position < text.Length; position++)
        {
            switch (text[position])
            {
                case '\r' when position + 1 < text.Length && text[position + 1] == '\n':
                    position++;
                    starts.Add(position + 1);
                    break;
                case '\r':
                case '\n':
                    starts.Add(position + 1);
                    break;
            }
        }

        return [.. starts];
    }

    private void ValidateSpan(TextSpan span)
    {
        if (span.End > Length)
        {
            throw new ArgumentOutOfRangeException(nameof(span));
        }
    }
}

Web Proxy Viewer  |  New URL  |  Original Page