Add JSON text renderer (#1086)

* Add JsonText widget to render highlighted JSON

Closes #1051
This commit is contained in:
Patrik Svensson
2022-12-31 19:17:15 +01:00
committed by GitHub
parent 3e6e0990c5
commit 54be64ec84
48 changed files with 1634 additions and 21 deletions

View File

@@ -0,0 +1,9 @@
namespace Spectre.Console.Internal;
internal static partial class CharExtensions
{
public static bool IsDigit(this char character, int min = 0)
{
return char.IsDigit(character) && character >= (char)min;
}
}

View File

@@ -0,0 +1,127 @@
namespace Spectre.Console;
internal static class EnumerableExtensions
{
// List.Reverse clashes with IEnumerable<T>.Reverse, so this method only exists
// so we won't have to cast List<T> to IEnumerable<T>.
public static IEnumerable<T> ReverseEnumerable<T>(this IEnumerable<T> source)
{
if (source is null)
{
throw new ArgumentNullException(nameof(source));
}
return source.Reverse();
}
public static bool None<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
return !source.Any(predicate);
}
public static IEnumerable<T> Repeat<T>(this IEnumerable<T> source, int count)
{
while (count-- > 0)
{
foreach (var item in source)
{
yield return item;
}
}
}
public static int IndexOf<T>(this IEnumerable<T> source, T item)
where T : class
{
var index = 0;
foreach (var candidate in source)
{
if (candidate == item)
{
return index;
}
index++;
}
return -1;
}
public static int GetCount<T>(this IEnumerable<T> source)
{
if (source is IList<T> list)
{
return list.Count;
}
if (source is T[] array)
{
return array.Length;
}
return source.Count();
}
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var item in source)
{
action(item);
}
}
public static bool AnyTrue(this IEnumerable<bool> source)
{
return source.Any(b => b);
}
public static IEnumerable<(int Index, bool First, bool Last, T Item)> Enumerate<T>(this IEnumerable<T> source)
{
if (source is null)
{
throw new ArgumentNullException(nameof(source));
}
return Enumerate(source.GetEnumerator());
}
public static IEnumerable<(int Index, bool First, bool Last, T Item)> Enumerate<T>(this IEnumerator<T> source)
{
if (source is null)
{
throw new ArgumentNullException(nameof(source));
}
var first = true;
var last = !source.MoveNext();
T current;
for (var index = 0; !last; index++)
{
current = source.Current;
last = !source.MoveNext();
yield return (index, first, last, current);
first = false;
}
}
public static IEnumerable<TResult> SelectIndex<T, TResult>(this IEnumerable<T> source, Func<T, int, TResult> func)
{
return source.Select((value, index) => func(value, index));
}
#if !NET6_0_OR_GREATER
public static IEnumerable<(TFirst First, TSecond Second)> Zip<TFirst, TSecond>(
this IEnumerable<TFirst> source, IEnumerable<TSecond> first)
{
return source.Zip(first, (first, second) => (first, second));
}
#endif
public static IEnumerable<(TFirst First, TSecond Second, TThird Third)> ZipThree<TFirst, TSecond, TThird>(
this IEnumerable<TFirst> first, IEnumerable<TSecond> second, IEnumerable<TThird> third)
{
return first.Zip(second, (a, b) => (a, b))
.Zip(third, (a, b) => (a.a, a.b, b));
}
}

View File

@@ -89,7 +89,7 @@ internal static class Ratio
var totalRemaining = total;
var result = new List<int>();
foreach (var (ratio, maximum, value) in ratios.Zip(maximums, values))
foreach (var (ratio, maximum, value) in ratios.ZipThree(maximums, values))
{
if (ratio != 0 && totalRatio > 0)
{

View File

@@ -23,11 +23,22 @@ internal sealed class StringBuffer : IDisposable
_reader.Dispose();
}
public char Expect(char character)
{
var read = Read();
if (read != character)
{
throw new InvalidOperationException($"Expected '{character}', but found '{read}'");
}
return read;
}
public char Peek()
{
if (Eof)
{
throw new InvalidOperationException("Tried to peek past the end of the text.");
return '\0';
}
return (char)_reader.Peek();
@@ -37,7 +48,7 @@ internal sealed class StringBuffer : IDisposable
{
if (Eof)
{
throw new InvalidOperationException("Tried to read past the end of the text.");
return '\0';
}
Position++;