-
-
Notifications
You must be signed in to change notification settings - Fork 489
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial JSON parser and renderer. Not very pretty 😅
- Loading branch information
1 parent
c1e9c1a
commit bb820c2
Showing
18 changed files
with
604 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net7.0</TargetFramework> | ||
<ExampleTitle>Json</ExampleTitle> | ||
<ExampleDescription>Displays the capabilities of the current console.</ExampleDescription> | ||
<ExampleGroup>Misc</ExampleGroup> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\Shared\Shared.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
using Spectre.Console; | ||
|
||
namespace Info; | ||
|
||
public static class Program | ||
{ | ||
public static void Main() | ||
{ | ||
var json = new JsonText("{ \"hello\": 32, \"World\": { \"foo\": 21, \"bar\": 255 } }"); | ||
AnsiConsole.Write( | ||
new Panel(new Padder(json, new Padding(2, 1))) | ||
{ | ||
Width = 35, | ||
} | ||
.Header("Some JSON in a panel") | ||
.Collapse() | ||
.RoundedBorder() | ||
.BorderColor(Color.Yellow)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
namespace Spectre.Console; | ||
|
||
internal static class JsonParser | ||
{ | ||
public static JsonSyntax Parse(List<JsonToken> tokens) | ||
{ | ||
var reader = new JsonTokenReader(tokens); | ||
return Parse(reader); | ||
} | ||
|
||
private static JsonSyntax Parse(JsonTokenReader reader) | ||
{ | ||
var current = reader.Peek(); | ||
if (current?.Type != JsonTokenType.LeftBrace) | ||
{ | ||
throw new InvalidOperationException("Invalid JSON"); | ||
} | ||
|
||
return ParseObject(reader); | ||
} | ||
|
||
private static JsonSyntax ParseObject(JsonTokenReader reader) | ||
{ | ||
reader.Consume(JsonTokenType.LeftBrace); | ||
|
||
var result = new JsonObject(); | ||
|
||
if (reader.Peek()?.Type != JsonTokenType.RightBrace) | ||
{ | ||
while (true) | ||
{ | ||
var name = reader.Consume(JsonTokenType.String); | ||
reader.Consume(JsonTokenType.Colon); | ||
var value = ParseValue(reader); | ||
|
||
result.Properties.Add(new JsonProperty(name.Lexeme, value)); | ||
|
||
if (reader.Peek()?.Type != JsonTokenType.Comma) | ||
{ | ||
break; | ||
} | ||
|
||
reader.Consume(JsonTokenType.Comma); | ||
} | ||
} | ||
|
||
reader.Consume(JsonTokenType.RightBrace); | ||
return result; | ||
} | ||
|
||
private static JsonSyntax ParseValue(JsonTokenReader reader) | ||
{ | ||
var current = reader.Peek(); | ||
if (current == null) | ||
{ | ||
throw new InvalidOperationException("Could not parse value"); | ||
} | ||
|
||
if (current.Type == JsonTokenType.LeftBrace) | ||
{ | ||
return ParseObject(reader); | ||
} | ||
|
||
if (current.Type == JsonTokenType.Number) | ||
{ | ||
reader.Consume(JsonTokenType.Number); | ||
return new JsonNumber(current.Lexeme); | ||
} | ||
|
||
throw new InvalidOperationException("Unknown value token"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
namespace Spectre.Console; | ||
|
||
public sealed class JsonText : JustInTimeRenderable | ||
{ | ||
private readonly JsonSyntax _syntax; | ||
|
||
public JsonText(string json) | ||
{ | ||
var tokens = JsonTokenizer.Tokenize(json); | ||
_syntax = JsonParser.Parse(tokens); | ||
} | ||
|
||
protected override IRenderable Build() | ||
{ | ||
var paragraph = new Paragraph(); | ||
_syntax.Accept(JsonParagraphCreator.Shared, new JsonContext(paragraph, new JsonTextStyles())); | ||
return paragraph; | ||
} | ||
|
||
private sealed class JsonParagraphCreator : JsonSyntaxVisitor<JsonContext> | ||
{ | ||
public static JsonParagraphCreator Shared { get; } = new JsonParagraphCreator(); | ||
|
||
public override void VisitNumber(JsonNumber syntax, JsonContext context) | ||
{ | ||
context.Paragraph.Append(syntax.Lexeme, new Style(Color.Red)); | ||
} | ||
|
||
public override void VisitObject(JsonObject syntax, JsonContext context) | ||
{ | ||
context.Paragraph.Append("{"); | ||
context.Paragraph.Append("\n"); | ||
context.IncreaseIndentation(); | ||
|
||
foreach (var (_, _, last, property) in syntax.Properties.Enumerate()) | ||
{ | ||
context.InsertIndentation(); | ||
property.Accept(this, context); | ||
|
||
if (!last) | ||
{ | ||
context.Paragraph.Append(",", new Style(Color.Green)); | ||
} | ||
|
||
context.Paragraph.Append("\n"); | ||
} | ||
|
||
context.DecreaseIndentation(); | ||
context.InsertIndentation(); | ||
context.Paragraph.Append("}"); | ||
} | ||
|
||
public override void VisitProperty(JsonProperty syntax, JsonContext context) | ||
{ | ||
context.Paragraph.Append(syntax.Name, new Style(Color.Blue)); | ||
context.Paragraph.Append(":", new Style(Color.Yellow)); | ||
context.Paragraph.Append(" "); | ||
|
||
syntax.Value.Accept(this, context); | ||
} | ||
} | ||
} | ||
|
||
internal sealed class JsonContext | ||
{ | ||
public Paragraph Paragraph { get; } | ||
public int Indentation { get; private set; } | ||
public JsonTextStyles Styling { get; } | ||
|
||
public JsonContext(Paragraph paragraph, JsonTextStyles styling) | ||
{ | ||
Paragraph = paragraph; | ||
Styling = styling; | ||
} | ||
|
||
public void IncreaseIndentation() | ||
{ | ||
Indentation++; | ||
} | ||
|
||
public void DecreaseIndentation() | ||
{ | ||
Indentation = Math.Max(0, Indentation - 1); | ||
} | ||
|
||
public void InsertIndentation() | ||
{ | ||
Paragraph.Append(new string(' ', Indentation * 3)); | ||
} | ||
} | ||
|
||
internal sealed class JsonTextStyles | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
namespace Spectre.Console; | ||
|
||
internal sealed class JsonToken | ||
{ | ||
public JsonTokenType Type { get; } | ||
public string Lexeme { get; } | ||
|
||
public JsonToken(JsonTokenType type, string lexeme) | ||
{ | ||
Type = type; | ||
Lexeme = lexeme ?? throw new ArgumentNullException(nameof(lexeme)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
namespace Spectre.Console; | ||
|
||
internal sealed class JsonTokenReader | ||
{ | ||
private readonly List<JsonToken> _reader; | ||
private readonly int _length; | ||
|
||
public int Position { get; private set; } | ||
public bool Eof => Position >= _length; | ||
|
||
public JsonTokenReader(List<JsonToken> tokens) | ||
{ | ||
_reader = tokens; | ||
_length = tokens.Count; | ||
|
||
Position = 0; | ||
} | ||
|
||
public JsonToken Consume(JsonTokenType type) | ||
{ | ||
var read = Read(); | ||
if (read?.Type != type) | ||
{ | ||
throw new InvalidOperationException($"Expected '{type}' token"); | ||
} | ||
|
||
return read; | ||
} | ||
|
||
public JsonToken? Peek() | ||
{ | ||
if (Eof) | ||
{ | ||
return null; | ||
} | ||
|
||
return _reader[Position]; | ||
} | ||
|
||
public JsonToken? Read() | ||
{ | ||
if (Eof) | ||
{ | ||
return null; | ||
} | ||
|
||
Position++; | ||
return _reader[Position - 1]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
namespace Spectre.Console; | ||
|
||
internal enum JsonTokenType | ||
{ | ||
LeftBrace, | ||
RightBrace, | ||
LeftBracket, | ||
RightBracket, | ||
Colon, | ||
Comma, | ||
String, | ||
Number, | ||
Boolean, | ||
Null, | ||
} |
Oops, something went wrong.