mirror of
				https://github.com/nsnail/spectre.console.git
				synced 2025-10-31 09:09:25 +08:00 
			
		
		
		
	Add column support
Adds support for rendering arbitrary data into columns. Closes #67
This commit is contained in:
		 Patrik Svensson
					Patrik Svensson
				
			
				
					committed by
					
						 Patrik Svensson
						Patrik Svensson
					
				
			
			
				
	
			
			
			 Patrik Svensson
						Patrik Svensson
					
				
			
						parent
						
							e946289bd9
						
					
				
				
					commit
					ae6d2c63a3
				
			
							
								
								
									
										17
									
								
								examples/Columns/Columns.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								examples/Columns/Columns.csproj
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>netcoreapp3.1</TargetFramework> | ||||
|     <IsPackable>false</IsPackable> | ||||
|   </PropertyGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="..\..\src\Spectre.Console\Spectre.Console.csproj" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
| </Project> | ||||
							
								
								
									
										42
									
								
								examples/Columns/Program.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								examples/Columns/Program.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Linq; | ||||
| using System.Net.Http; | ||||
| using System.Threading.Tasks; | ||||
| using Newtonsoft.Json.Linq; | ||||
| using Spectre.Console; | ||||
| using Spectre.Console.Rendering; | ||||
|  | ||||
| namespace ColumnsExample | ||||
| { | ||||
|     public static class Program | ||||
|     { | ||||
|         public static async Task Main() | ||||
|         { | ||||
|             // Download some random users | ||||
|             using var client = new HttpClient(); | ||||
|             dynamic users = JObject.Parse( | ||||
|                 await client.GetStringAsync("https://randomuser.me/api/?results=15")); | ||||
|  | ||||
|             // Create a card for each user | ||||
|             var cards = new List<Panel>(); | ||||
|             foreach(var user in users.results) | ||||
|             { | ||||
|                 cards.Add(new Panel(GetCard(user)) | ||||
|                     .SetHeader($"{user.location.country}") | ||||
|                     .RoundedBorder().Expand()); | ||||
|             } | ||||
|  | ||||
|             // Render all cards in columns | ||||
|             AnsiConsole.Render(new Columns(cards)); | ||||
|         } | ||||
|  | ||||
|         private static string GetCard(dynamic user) | ||||
|         { | ||||
|             var name = $"{user.name.first} {user.name.last}"; | ||||
|             var country = $"{user.location.city}"; | ||||
|  | ||||
|             return $"[b]{name}[/]\n[yellow]{country}[/]"; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,4 +1,3 @@ | ||||
| using System; | ||||
| using Spectre.Console; | ||||
|  | ||||
| namespace Diagnostic | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| using Spectre.Console; | ||||
| using Spectre.Console.Rendering; | ||||
|  | ||||
| namespace TableExample | ||||
| { | ||||
|   | ||||
| @@ -82,5 +82,8 @@ dotnet_diagnostic.RCS1079.severity = warning | ||||
| # RCS1057: Add empty line between declarations. | ||||
| dotnet_diagnostic.RCS1057.severity = none | ||||
|  | ||||
| # RCS1057: Validate arguments correctly | ||||
| dotnet_diagnostic.RCS1227.severity = none | ||||
|  | ||||
| # IDE0004: Remove Unnecessary Cast | ||||
| dotnet_diagnostic.IDE0004.severity = warning | ||||
							
								
								
									
										46
									
								
								src/Spectre.Console.Tests/Unit/ColumnsTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/Spectre.Console.Tests/Unit/ColumnsTests.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| using System.Collections.Generic; | ||||
| using Shouldly; | ||||
| using Xunit; | ||||
|  | ||||
| namespace Spectre.Console.Tests.Unit | ||||
| { | ||||
|     public sealed class ColumnsTests | ||||
|     { | ||||
|         private sealed class User | ||||
|         { | ||||
|             public string Name { get; set; } | ||||
|             public string Country { get; set; } | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void Should_Render_Columns_Correctly() | ||||
|         { | ||||
|             // Given | ||||
|             var console = new PlainConsole(width: 61); | ||||
|             var users = new[] | ||||
|             { | ||||
|                 new User { Name = "Savannah Thompson", Country = "Australia" }, | ||||
|                 new User { Name = "Sophie Ramos", Country = "United States" }, | ||||
|                 new User { Name = "Katrin Goldberg", Country = "Germany" }, | ||||
|             }; | ||||
|  | ||||
|             var cards = new List<Panel>(); | ||||
|             foreach (var user in users) | ||||
|             { | ||||
|                 cards.Add( | ||||
|                     new Panel($"[b]{user.Name}[/]\n[yellow]{user.Country}[/]") | ||||
|                         .RoundedBorder().Expand()); | ||||
|             } | ||||
|  | ||||
|             // When | ||||
|             console.Render(new Columns(cards)); | ||||
|  | ||||
|             // Then | ||||
|             console.Lines.Count.ShouldBe(4); | ||||
|             console.Lines[0].ShouldBe("╭────────────────────╮ ╭────────────────╮ ╭─────────────────╮"); | ||||
|             console.Lines[1].ShouldBe("│ Savannah Thompson  │ │ Sophie Ramos   │ │ Katrin Goldberg │"); | ||||
|             console.Lines[2].ShouldBe("│ Australia          │ │ United States  │ │ Germany         │"); | ||||
|             console.Lines[3].ShouldBe("╰────────────────────╯ ╰────────────────╯ ╰─────────────────╯"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -42,7 +42,7 @@ namespace Spectre.Console.Tests.Unit | ||||
|             } | ||||
|  | ||||
|             [Fact] | ||||
|             public void Should_Throw_If_Row_Columns_Is_Less_Than_Number_Of_Columns() | ||||
|             public void Should_Add_Empty_Items_If_User_Provides_Less_Row_Items_Than_Columns() | ||||
|             { | ||||
|                 // Given | ||||
|                 var grid = new Grid(); | ||||
| @@ -50,11 +50,10 @@ namespace Spectre.Console.Tests.Unit | ||||
|                 grid.AddColumn(); | ||||
|  | ||||
|                 // When | ||||
|                 var result = Record.Exception(() => grid.AddRow("Foo")); | ||||
|                 grid.AddRow("Foo"); | ||||
|  | ||||
|                 // Then | ||||
|                 result.ShouldBeOfType<InvalidOperationException>(); | ||||
|                 result.Message.ShouldBe("The number of row columns are less than the number of grid columns."); | ||||
|                 grid.RowCount.ShouldBe(1); | ||||
|             } | ||||
|  | ||||
|             [Fact] | ||||
|   | ||||
| @@ -87,7 +87,7 @@ namespace Spectre.Console.Tests.Unit | ||||
|             } | ||||
|  | ||||
|             [Fact] | ||||
|             public void Should_Throw_If_Row_Columns_Is_Less_Than_Number_Of_Columns() | ||||
|             public void Should_Add_Empty_Items_If_User_Provides_Less_Row_Items_Than_Columns() | ||||
|             { | ||||
|                 // Given | ||||
|                 var table = new Table(); | ||||
| @@ -95,11 +95,10 @@ namespace Spectre.Console.Tests.Unit | ||||
|                 table.AddColumn("World"); | ||||
|  | ||||
|                 // When | ||||
|                 var result = Record.Exception(() => table.AddRow("Foo")); | ||||
|                 table.AddRow("Foo"); | ||||
|  | ||||
|                 // Then | ||||
|                 result.ShouldBeOfType<InvalidOperationException>(); | ||||
|                 result.Message.ShouldBe("The number of row columns are less than the number of table columns."); | ||||
|                 table.RowCount.ShouldBe(1); | ||||
|             } | ||||
|  | ||||
|             [Fact] | ||||
|   | ||||
| @@ -65,6 +65,21 @@ namespace Spectre.Console.Tests.Unit | ||||
|             fixture.RawOutput.ShouldBe("Hello\n\nWorld\n\n"); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void Should_Render_Panel_2() | ||||
|         { | ||||
|             // Given | ||||
|             var console = new PlainConsole(width: 80); | ||||
|  | ||||
|             // When | ||||
|             console.Render(new Markup("[b]Hello World[/]\n[yellow]Hello World[/]")); | ||||
|  | ||||
|             // Then | ||||
|             console.Lines.Count.ShouldBe(2); | ||||
|             console.Lines[0].ShouldBe("Hello World"); | ||||
|             console.Lines[1].ShouldBe("Hello World"); | ||||
|         } | ||||
|  | ||||
|         [Theory] | ||||
|         [InlineData(5, "Hello World", "Hello\nWorld")] | ||||
|         [InlineData(10, "Hello Sweet Nice World", "Hello \nSweet Nice\nWorld")] | ||||
|   | ||||
| @@ -27,6 +27,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Colors", "..\examples\Color | ||||
| EndProject | ||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Diagnostic", "..\examples\Diagnostic\Diagnostic.csproj", "{4337F255-88E9-4408-81A3-DF1AF58AC753}" | ||||
| EndProject | ||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Columns", "..\examples\Columns\Columns.csproj", "{33357599-C79D-4299-888F-634E2C3EACEF}" | ||||
| EndProject | ||||
| Global | ||||
| 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||
| 		Debug|Any CPU = Debug|Any CPU | ||||
| @@ -121,6 +123,18 @@ Global | ||||
| 		{4337F255-88E9-4408-81A3-DF1AF58AC753}.Release|x64.Build.0 = Release|Any CPU | ||||
| 		{4337F255-88E9-4408-81A3-DF1AF58AC753}.Release|x86.ActiveCfg = Release|Any CPU | ||||
| 		{4337F255-88E9-4408-81A3-DF1AF58AC753}.Release|x86.Build.0 = Release|Any CPU | ||||
| 		{33357599-C79D-4299-888F-634E2C3EACEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||
| 		{33357599-C79D-4299-888F-634E2C3EACEF}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
| 		{33357599-C79D-4299-888F-634E2C3EACEF}.Debug|x64.ActiveCfg = Debug|Any CPU | ||||
| 		{33357599-C79D-4299-888F-634E2C3EACEF}.Debug|x64.Build.0 = Debug|Any CPU | ||||
| 		{33357599-C79D-4299-888F-634E2C3EACEF}.Debug|x86.ActiveCfg = Debug|Any CPU | ||||
| 		{33357599-C79D-4299-888F-634E2C3EACEF}.Debug|x86.Build.0 = Debug|Any CPU | ||||
| 		{33357599-C79D-4299-888F-634E2C3EACEF}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||
| 		{33357599-C79D-4299-888F-634E2C3EACEF}.Release|Any CPU.Build.0 = Release|Any CPU | ||||
| 		{33357599-C79D-4299-888F-634E2C3EACEF}.Release|x64.ActiveCfg = Release|Any CPU | ||||
| 		{33357599-C79D-4299-888F-634E2C3EACEF}.Release|x64.Build.0 = Release|Any CPU | ||||
| 		{33357599-C79D-4299-888F-634E2C3EACEF}.Release|x86.ActiveCfg = Release|Any CPU | ||||
| 		{33357599-C79D-4299-888F-634E2C3EACEF}.Release|x86.Build.0 = Release|Any CPU | ||||
| 	EndGlobalSection | ||||
| 	GlobalSection(SolutionProperties) = preSolution | ||||
| 		HideSolutionNode = FALSE | ||||
| @@ -131,6 +145,7 @@ Global | ||||
| 		{C7FF6FDB-FB59-4517-8669-521C96AB7323} = {F0575243-121F-4DEE-9F6B-246E26DC0844} | ||||
| 		{1F51C55C-BA4C-4856-9001-0F7924FFB179} = {F0575243-121F-4DEE-9F6B-246E26DC0844} | ||||
| 		{4337F255-88E9-4408-81A3-DF1AF58AC753} = {F0575243-121F-4DEE-9F6B-246E26DC0844} | ||||
| 		{33357599-C79D-4299-888F-634E2C3EACEF} = {F0575243-121F-4DEE-9F6B-246E26DC0844} | ||||
| 	EndGlobalSection | ||||
| 	GlobalSection(ExtensibilityGlobals) = postSolution | ||||
| 		SolutionGuid = {5729B071-67A0-48FB-8B1B-275E6822086C} | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| using System; | ||||
| using System.Linq; | ||||
| using Spectre.Console.Internal; | ||||
| using Spectre.Console.Rendering; | ||||
|  | ||||
| @@ -30,8 +31,8 @@ namespace Spectre.Console | ||||
|  | ||||
|             using (console.PushStyle(Style.Plain)) | ||||
|             { | ||||
|                 var segments = renderable.Render(options, console.Width); | ||||
|                 segments = Segment.Merge(segments); | ||||
|                 var segments = renderable.Render(options, console.Width).Where(x => !(x.Text.Length == 0 && !x.IsLineBreak)).ToArray(); | ||||
|                 segments = Segment.Merge(segments).ToArray(); | ||||
|  | ||||
|                 var current = Style.Plain; | ||||
|                 foreach (var segment in segments) | ||||
|   | ||||
							
								
								
									
										141
									
								
								src/Spectre.Console/Rendering/Columns.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								src/Spectre.Console/Rendering/Columns.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using Spectre.Console.Rendering; | ||||
|  | ||||
| namespace Spectre.Console | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Renders things in columns. | ||||
|     /// </summary> | ||||
|     public sealed class Columns : Renderable, IPaddable, IExpandable | ||||
|     { | ||||
|         private readonly List<IRenderable> _items; | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         public Padding Padding { get; set; } = new Padding(0, 1); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets a value indicating whether or not the columns should | ||||
|         /// expand to the available space. If <c>false</c>, the column | ||||
|         /// width will be auto calculated. Defaults to <c>true</c>. | ||||
|         /// </summary> | ||||
|         public bool Expand { get; set; } = true; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Initializes a new instance of the <see cref="Columns"/> class. | ||||
|         /// </summary> | ||||
|         /// <param name="items">The items to render.</param> | ||||
|         public Columns(IEnumerable<IRenderable> items) | ||||
|         { | ||||
|             if (items is null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(items)); | ||||
|             } | ||||
|  | ||||
|             _items = new List<IRenderable>(items); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Initializes a new instance of the <see cref="Columns"/> class. | ||||
|         /// </summary> | ||||
|         /// <param name="items">The items to render.</param> | ||||
|         public Columns(IEnumerable<string> items) | ||||
|         { | ||||
|             if (items is null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(items)); | ||||
|             } | ||||
|  | ||||
|             _items = new List<IRenderable>(items.Select(item => new Markup(item))); | ||||
|         } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         protected override IEnumerable<Segment> Render(RenderContext context, int maxWidth) | ||||
|         { | ||||
|             var maxPadding = Math.Max(Padding.Left, Padding.Right); | ||||
|  | ||||
|             var itemWidths = _items.Select(item => item.Measure(context, maxWidth).Max).ToArray(); | ||||
|             var columnCount = CalculateColumnCount(maxWidth, itemWidths, _items.Count, maxPadding); | ||||
|  | ||||
|             var table = new Table(); | ||||
|             table.NoBorder(); | ||||
|             table.HideHeaders(); | ||||
|             table.PadRightCell = false; | ||||
|  | ||||
|             if (Expand) | ||||
|             { | ||||
|                 table.Expand(); | ||||
|             } | ||||
|  | ||||
|             // Add columns | ||||
|             for (var index = 0; index < columnCount; index++) | ||||
|             { | ||||
|                 table.AddColumn(new TableColumn(string.Empty) | ||||
|                 { | ||||
|                     Padding = Padding, | ||||
|                     NoWrap = true, | ||||
|                 }); | ||||
|             } | ||||
|  | ||||
|             // Add rows | ||||
|             for (var start = 0; start < _items.Count; start += columnCount) | ||||
|             { | ||||
|                 table.AddRow(_items.Skip(start).Take(columnCount).ToArray()); | ||||
|             } | ||||
|  | ||||
|             return ((IRenderable)table).Render(context, maxWidth); | ||||
|         } | ||||
|  | ||||
|         // Algorithm borrowed from https://github.com/willmcgugan/rich/blob/master/rich/columns.py | ||||
|         private int CalculateColumnCount(int maxWidth, int[] itemWidths, int columnCount, int padding) | ||||
|         { | ||||
|             var widths = new Dictionary<int, int>(); | ||||
|             while (columnCount > 1) | ||||
|             { | ||||
|                 var columnIndex = 0; | ||||
|                 widths.Clear(); | ||||
|  | ||||
|                 var exceededTotalWidth = false; | ||||
|                 foreach (var renderableWidth in IterateWidths(itemWidths, columnCount)) | ||||
|                 { | ||||
|                     widths[columnIndex] = Math.Max(widths.ContainsKey(columnIndex) ? widths[columnIndex] : 0, renderableWidth); | ||||
|                     var totalWidth = widths.Values.Sum() + (padding * (widths.Count - 1)); | ||||
|                     if (totalWidth > maxWidth) | ||||
|                     { | ||||
|                         columnCount = widths.Count - 1; | ||||
|                         exceededTotalWidth = true; | ||||
|                         break; | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         columnIndex = (columnIndex + 1) % columnCount; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 if (!exceededTotalWidth) | ||||
|                 { | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             return columnCount; | ||||
|         } | ||||
|  | ||||
|         private IEnumerable<int> IterateWidths(int[] itemWidths, int columnCount) | ||||
|         { | ||||
|             foreach (var width in itemWidths) | ||||
|             { | ||||
|                 yield return width; | ||||
|             } | ||||
|  | ||||
|             if (_items.Count % columnCount != 0) | ||||
|             { | ||||
|                 for (var i = 0; i < columnCount - (_items.Count % columnCount) - 1; i++) | ||||
|                 { | ||||
|                     yield return 0; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -7,7 +7,7 @@ namespace Spectre.Console | ||||
|     /// <summary> | ||||
|     /// A renderable grid. | ||||
|     /// </summary> | ||||
|     public sealed class Grid : Renderable | ||||
|     public sealed class Grid : Renderable, IExpandable | ||||
|     { | ||||
|         private readonly Table _table; | ||||
|  | ||||
| @@ -21,6 +21,13 @@ namespace Spectre.Console | ||||
|         /// </summary> | ||||
|         public int RowCount => _table.RowCount; | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         public bool Expand | ||||
|         { | ||||
|             get => _table.Expand; | ||||
|             set => _table.Expand = value; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Initializes a new instance of the <see cref="Grid"/> class. | ||||
|         /// </summary> | ||||
| @@ -94,11 +101,6 @@ namespace Spectre.Console | ||||
|                 throw new ArgumentNullException(nameof(columns)); | ||||
|             } | ||||
|  | ||||
|             if (columns.Length < _table.ColumnCount) | ||||
|             { | ||||
|                 throw new InvalidOperationException("The number of row columns are less than the number of grid columns."); | ||||
|             } | ||||
|  | ||||
|             if (columns.Length > _table.ColumnCount) | ||||
|             { | ||||
|                 throw new InvalidOperationException("The number of row columns are greater than the number of grid columns."); | ||||
|   | ||||
| @@ -64,8 +64,8 @@ namespace Spectre.Console | ||||
|         { | ||||
|             var childWidth = _child.Measure(context, maxWidth); | ||||
|             return new Measurement( | ||||
|                 childWidth.Min + 2 + Padding.GetHorizontalPadding(), | ||||
|                 childWidth.Max + 2 + Padding.GetHorizontalPadding()); | ||||
|                 childWidth.Min + EdgeWidth + Padding.GetHorizontalPadding(), | ||||
|                 childWidth.Max + EdgeWidth + Padding.GetHorizontalPadding()); | ||||
|         } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|   | ||||
| @@ -13,10 +13,25 @@ namespace Spectre.Console.Rendering | ||||
|     [DebuggerDisplay("{Text,nq}")] | ||||
|     public class Segment | ||||
|     { | ||||
|         private readonly bool _mutable; | ||||
|         private string _text; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets the segment text. | ||||
|         /// </summary> | ||||
|         public string Text { get; internal set; } | ||||
|         public string Text | ||||
|         { | ||||
|             get => _text; | ||||
|             private set | ||||
|             { | ||||
|                 if (!_mutable) | ||||
|                 { | ||||
|                     throw new NotSupportedException(); | ||||
|                 } | ||||
|  | ||||
|                 _text = value; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets a value indicating whether or not this is an expicit line break | ||||
| @@ -39,12 +54,12 @@ namespace Spectre.Console.Rendering | ||||
|         /// <summary> | ||||
|         /// Gets a segment representing a line break. | ||||
|         /// </summary> | ||||
|         public static Segment LineBreak { get; } = new Segment(Environment.NewLine, Style.Plain, true); | ||||
|         public static Segment LineBreak { get; } = new Segment(Environment.NewLine, Style.Plain, true, false); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets an empty segment. | ||||
|         /// </summary> | ||||
|         public static Segment Empty { get; } = new Segment(string.Empty, Style.Plain); | ||||
|         public static Segment Empty { get; } = new Segment(string.Empty, Style.Plain, false, false); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Initializes a new instance of the <see cref="Segment"/> class. | ||||
| @@ -65,14 +80,16 @@ namespace Spectre.Console.Rendering | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         private Segment(string text, Style style, bool lineBreak) | ||||
|         private Segment(string text, Style style, bool lineBreak, bool mutable = true) | ||||
|         { | ||||
|             if (text is null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(text)); | ||||
|             } | ||||
|  | ||||
|             Text = text.NormalizeLineEndings(); | ||||
|             _mutable = mutable; | ||||
|             _text = text.NormalizeLineEndings(); | ||||
|  | ||||
|             Style = style; | ||||
|             IsLineBreak = lineBreak; | ||||
|             IsWhiteSpace = string.IsNullOrWhiteSpace(text); | ||||
|   | ||||
| @@ -18,7 +18,7 @@ namespace Spectre.Console | ||||
|         // https://github.com/willmcgugan/rich/blob/527475837ebbfc427530b3ee0d4d0741d2d0fc6d/rich/table.py#L394 | ||||
|         private List<int> CalculateColumnWidths(RenderContext options, int maxWidth) | ||||
|         { | ||||
|             var width_ranges = _columns.Select(column => MeasureColumn(column, options, maxWidth)); | ||||
|             var width_ranges = _columns.Select(column => MeasureColumn(column, options, maxWidth)).ToArray(); | ||||
|             var widths = width_ranges.Select(range => range.Max).ToList(); | ||||
|  | ||||
|             var tableWidth = widths.Sum(); | ||||
| @@ -117,9 +117,17 @@ namespace Spectre.Console | ||||
|  | ||||
|         private int GetExtraWidth(bool includePadding) | ||||
|         { | ||||
|             var separators = _columns.Count - 1; | ||||
|             var hideBorder = BorderKind == BorderKind.None; | ||||
|             var separators = hideBorder ? 0 : _columns.Count - 1; | ||||
|             var edges = hideBorder ? 0 : EdgeCount; | ||||
|             var padding = includePadding ? _columns.Select(x => x.Padding.GetHorizontalPadding()).Sum() : 0; | ||||
|             return separators + EdgeCount + padding; | ||||
|  | ||||
|             if (!PadRightCell) | ||||
|             { | ||||
|                 padding -= _columns.Last().Padding.Right; | ||||
|             } | ||||
|  | ||||
|             return separators + edges + padding; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -125,17 +125,19 @@ namespace Spectre.Console | ||||
|                 throw new ArgumentNullException(nameof(columns)); | ||||
|             } | ||||
|  | ||||
|             if (columns.Length < _columns.Count) | ||||
|             { | ||||
|                 throw new InvalidOperationException("The number of row columns are less than the number of table columns."); | ||||
|             } | ||||
|  | ||||
|             if (columns.Length > _columns.Count) | ||||
|             { | ||||
|                 throw new InvalidOperationException("The number of row columns are greater than the number of table columns."); | ||||
|             } | ||||
|  | ||||
|             _rows.Add(columns.ToList()); | ||||
|  | ||||
|             // Need to add missing columns? | ||||
|             if (columns.Length < _columns.Count) | ||||
|             { | ||||
|                 var diff = _columns.Count - columns.Length; | ||||
|                 Enumerable.Range(0, diff).ForEach(_ => _rows.Last().Add(Text.Empty)); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console.Rendering | ||||
| namespace Spectre.Console | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Contains extension methods for <see cref="IHasBorder"/>. | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console.Rendering | ||||
| namespace Spectre.Console | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Contains extension methods for <see cref="IExpandable"/>. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user