Add tree widget

This commit is contained in:
Matt Constable
2021-01-02 09:01:16 +00:00
committed by GitHub
parent 179e243214
commit b136d0299b
16 changed files with 467 additions and 16 deletions

View File

@ -0,0 +1,40 @@
Root node
├── child1
│ ├── multiple
│ │ line 0
│ ├── multiple
│ │ line 1
│ ├── multiple
│ │ line 2
│ ├── multiple
│ │ line 3
│ ├── multiple
│ │ line 4
│ ├── multiple
│ │ line 5
│ ├── multiple
│ │ line 6
│ ├── multiple
│ │ line 7
│ ├── multiple
│ │ line 8
│ └── multiple
│ line 9
├── child2
│ └── child2Child
│ └── Child 2 child
│ child
└── child3
└── single leaf
multiline
└── 2020 January
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ Sun │ Mon │ Tue │ Wed │ Thu │ Fri │ Sat │
├─────┼─────┼─────┼─────┼─────┼─────┼─────┤
│ │ │ │ 1 │ 2 │ 3 │ 4 │
│ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │
│ 12 │ 13 │ 14 │ 15 │ 16 │ 17 │ 18 │
│ 19 │ 20 │ 21 │ 22 │ 23 │ 24 │ 25 │
│ 26 │ 27 │ 28 │ 29 │ 30 │ 31 │ │
│ │ │ │ │ │ │ │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┘

View File

@ -0,0 +1,90 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Spectre.Console.Rendering;
using Xunit;
namespace Spectre.Console.Tests.Unit
{
public class TreeMeasureTests
{
[Fact]
public void Measure_Tree_Dominated_Width()
{
// Given
var nestedChildren =
Enumerable.Range(0, 10)
.Select(x => new TreeNode(new Text($"multiple \n line {x}")));
var child3 = new TreeNode(new Text("child3"));
child3.AddChild(new TreeNode(new Text("single leaf\n multiline")));
var children = new List<TreeNode>
{
new(new Text("child1"), nestedChildren), new(new Text("child2")), child3,
};
var root = new TreeNode(new Text("Root node"), children);
var tree = new Tree(root);
// When
var measurement = ((IRenderable)tree).Measure(new RenderContext(Encoding.Unicode, false), 80);
// Then
// Corresponds to "│ └── multiple"
Assert.Equal(17, measurement.Min);
// Corresponds to " └── single leaf" when untrimmed
Assert.Equal(19, measurement.Max);
}
[Fact]
public void Measure_Max_Width_Bound()
{
// Given
var root = new TreeNode(new Text("Root node"));
var currentNode = root;
foreach (var i in Enumerable.Range(0, 100))
{
var newNode = new TreeNode(new Text(string.Empty));
currentNode.AddChild(newNode);
currentNode = newNode;
}
var tree = new Tree(root);
// When
var measurement = ((IRenderable)tree).Measure(new RenderContext(Encoding.Unicode, false), 80);
// Then
// Each node depth contributes 4 characters, so 100 node depth -> 400 character min width
Assert.Equal(400, measurement.Min);
// Successfully capped at 80 terminal width
Assert.Equal(80, measurement.Max);
}
[Fact]
public void Measure_Leaf_Dominated_Width()
{
// Given
var root = new TreeNode(new Text("Root node"));
var currentNode = root;
foreach (var i in Enumerable.Range(0, 10))
{
var newNode = new TreeNode(new Text(string.Empty));
currentNode.AddChild(newNode);
currentNode = newNode;
}
var tree = new Tree(root);
// When
var measurement = ((IRenderable)tree).Measure(new RenderContext(Encoding.Unicode, false), 80);
// Then
// Corresponds to "│ │ │ │ │ │ │ │ │ └── "
Assert.Equal(40, measurement.Min);
// Corresponds to "│ │ │ │ │ │ │ │ │ └── "
Assert.Equal(40, measurement.Max);
}
}
}

View File

@ -0,0 +1,55 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Spectre.Console.Testing;
using VerifyXunit;
using Xunit;
namespace Spectre.Console.Tests.Unit
{
[UsesVerify]
public sealed class TreeRenderingTests
{
[Fact]
public Task Representative_Tree()
{
// Given
var console = new FakeConsole(width: 80);
var nestedChildren =
Enumerable.Range(0, 10)
.Select(x => new TreeNode(new Text($"multiple \n line {x}")));
var child2 = new TreeNode(new Text("child2"));
var child2Child = new TreeNode(new Text("child2Child"));
child2.AddChild(child2Child);
child2Child.AddChild(new TreeNode(new Text("Child 2 child\n child")));
var child3 = new TreeNode(new Text("child3"));
var child3Child = new TreeNode(new Text("single leaf\n multiline"));
child3Child.AddChild(new TreeNode(new Calendar(2020, 01)));
child3.AddChild(child3Child);
var children = new List<TreeNode> { new(new Text("child1"), nestedChildren), child2, child3 };
var root = new TreeNode(new Text("Root node"), children);
var tree = new Tree(root);
// When
console.Render(tree);
// Then
return Verifier.Verify(console.Output);
}
[Fact]
public Task Root_Node_Only()
{
// Given
var console = new FakeConsole(width: 80);
var root = new TreeNode(new Text("Root node"), Enumerable.Empty<TreeNode>());
var tree = new Tree(root);
// When
console.Render(tree);
// Then
return Verifier.Verify(console.Output);
}
}
}