mirror of
				https://github.com/nsnail/spectre.console.git
				synced 2025-10-31 09:09:25 +08:00 
			
		
		
		
	Add support for showing no border
This commit is contained in:
		
				
					committed by
					
						 Patrik Svensson
						Patrik Svensson
					
				
			
			
				
	
			
			
			
						parent
						
							a068fc68c3
						
					
				
				
					commit
					f9bd936254
				
			| @@ -111,7 +111,7 @@ namespace Spectre.Console.Tests.Unit.Composition | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void Should_Render_Table_With_Specified_Border() | ||||
|         public void Should_Render_Table_With_Specified_Border_Correctly() | ||||
|         { | ||||
|             // Given | ||||
|             var console = new PlainConsole(width: 80); | ||||
| @@ -132,6 +132,26 @@ namespace Spectre.Console.Tests.Unit.Composition | ||||
|             console.Lines[5].ShouldBe("+-------------------------+"); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void Should_Render_Table_With_No_Border_Correctly() | ||||
|         { | ||||
|             // Given | ||||
|             var console = new PlainConsole(width: 80); | ||||
|             var table = new Table(BorderKind.None); | ||||
|             table.AddColumns("Foo", "Bar", "Baz"); | ||||
|             table.AddRow("Qux", "Corgi", "Waldo"); | ||||
|             table.AddRow("Grault", "Garply", "Fred"); | ||||
|  | ||||
|             // When | ||||
|             console.Render(table); | ||||
|  | ||||
|             // Then | ||||
|             console.Lines.Count.ShouldBe(3); | ||||
|             console.Lines[0].ShouldBe("Foo     Bar     Baz  "); | ||||
|             console.Lines[1].ShouldBe("Qux     Corgi   Waldo"); | ||||
|             console.Lines[2].ShouldBe("Grault  Garply  Fred "); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void Should_Render_Table_With_Multiple_Rows_In_Cell_Correctly() | ||||
|         { | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Globalization; | ||||
| using System.Linq; | ||||
|  | ||||
| namespace Spectre.Console.Composition | ||||
| { | ||||
| @@ -9,10 +10,11 @@ namespace Spectre.Console.Composition | ||||
|     /// </summary> | ||||
|     public abstract class Border | ||||
|     { | ||||
|         private readonly Dictionary<BorderPart, char> _lookup; | ||||
|         private readonly Dictionary<BorderPart, string> _lookup; | ||||
|  | ||||
|         private static readonly Dictionary<BorderKind, Border> _borders = new Dictionary<BorderKind, Border> | ||||
|         { | ||||
|             { BorderKind.None, new NoBorder() }, | ||||
|             { BorderKind.Ascii, new AsciiBorder() }, | ||||
|             { BorderKind.Square, new SquareBorder() }, | ||||
|         }; | ||||
| @@ -40,11 +42,17 @@ namespace Spectre.Console.Composition | ||||
|             return border; | ||||
|         } | ||||
|  | ||||
|         private Dictionary<BorderPart, char> Initialize() | ||||
|         private Dictionary<BorderPart, string> Initialize() | ||||
|         { | ||||
|             var lookup = new Dictionary<BorderPart, char>(); | ||||
|             var lookup = new Dictionary<BorderPart, string>(); | ||||
|             foreach (BorderPart part in Enum.GetValues(typeof(BorderPart))) | ||||
|             { | ||||
|                 var text = GetBoxPart(part); | ||||
|                 if (text.Length > 1) | ||||
|                 { | ||||
|                     throw new InvalidOperationException("A box part cannot contain more than one character."); | ||||
|                 } | ||||
|  | ||||
|                 lookup.Add(part, GetBoxPart(part)); | ||||
|             } | ||||
|  | ||||
| @@ -59,7 +67,8 @@ namespace Spectre.Console.Composition | ||||
|         /// <returns>A string representation of the specified border part.</returns> | ||||
|         public string GetPart(BorderPart part, int count) | ||||
|         { | ||||
|             return new string(GetBoxPart(part), count); | ||||
|             // TODO: This need some optimization... | ||||
|             return string.Join(string.Empty, Enumerable.Repeat(GetBoxPart(part)[0], count)); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
| @@ -77,6 +86,6 @@ namespace Spectre.Console.Composition | ||||
|         /// </summary> | ||||
|         /// <param name="part">The part to get the character representation for.</param> | ||||
|         /// <returns>A character representation of the specified border part.</returns> | ||||
|         protected abstract char GetBoxPart(BorderPart part); | ||||
|         protected abstract string GetBoxPart(BorderPart part); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -5,14 +5,19 @@ namespace Spectre.Console | ||||
|     /// </summary> | ||||
|     public enum BorderKind | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// No border. | ||||
|         /// </summary> | ||||
|         None = 0, | ||||
|  | ||||
|         /// <summary> | ||||
|         /// A square border. | ||||
|         /// </summary> | ||||
|         Square = 0, | ||||
|         Square = 1, | ||||
|  | ||||
|         /// <summary> | ||||
|         /// An old school ASCII border. | ||||
|         /// </summary> | ||||
|         Ascii = 1, | ||||
|         Ascii = 2, | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -8,28 +8,28 @@ namespace Spectre.Console.Composition | ||||
|     public sealed class AsciiBorder : Border | ||||
|     { | ||||
|         /// <inheritdoc/> | ||||
|         protected override char GetBoxPart(BorderPart part) | ||||
|         protected override string GetBoxPart(BorderPart part) | ||||
|         { | ||||
|             return part switch | ||||
|             { | ||||
|                 BorderPart.HeaderTopLeft => '+', | ||||
|                 BorderPart.HeaderTop => '-', | ||||
|                 BorderPart.HeaderTopSeparator => '-', | ||||
|                 BorderPart.HeaderTopRight => '+', | ||||
|                 BorderPart.HeaderLeft => '|', | ||||
|                 BorderPart.HeaderSeparator => '|', | ||||
|                 BorderPart.HeaderRight => '|', | ||||
|                 BorderPart.HeaderBottomLeft => '|', | ||||
|                 BorderPart.HeaderBottom => '-', | ||||
|                 BorderPart.HeaderBottomSeparator => '+', | ||||
|                 BorderPart.HeaderBottomRight => '|', | ||||
|                 BorderPart.CellLeft => '|', | ||||
|                 BorderPart.CellSeparator => '|', | ||||
|                 BorderPart.ColumnRight => '|', | ||||
|                 BorderPart.FooterBottomLeft => '+', | ||||
|                 BorderPart.FooterBottom => '-', | ||||
|                 BorderPart.FooterBottomSeparator => '-', | ||||
|                 BorderPart.FooterBottomRight => '+', | ||||
|                 BorderPart.HeaderTopLeft => "+", | ||||
|                 BorderPart.HeaderTop => "-", | ||||
|                 BorderPart.HeaderTopSeparator => "-", | ||||
|                 BorderPart.HeaderTopRight => "+", | ||||
|                 BorderPart.HeaderLeft => "|", | ||||
|                 BorderPart.HeaderSeparator => "|", | ||||
|                 BorderPart.HeaderRight => "|", | ||||
|                 BorderPart.HeaderBottomLeft => "|", | ||||
|                 BorderPart.HeaderBottom => "-", | ||||
|                 BorderPart.HeaderBottomSeparator => "+", | ||||
|                 BorderPart.HeaderBottomRight => "|", | ||||
|                 BorderPart.CellLeft => "|", | ||||
|                 BorderPart.CellSeparator => "|", | ||||
|                 BorderPart.ColumnRight => "|", | ||||
|                 BorderPart.FooterBottomLeft => "+", | ||||
|                 BorderPart.FooterBottom => "-", | ||||
|                 BorderPart.FooterBottomSeparator => "-", | ||||
|                 BorderPart.FooterBottomRight => "+", | ||||
|                 _ => throw new InvalidOperationException("Unknown box part."), | ||||
|             }; | ||||
|         } | ||||
|   | ||||
							
								
								
									
										10
									
								
								src/Spectre.Console/Composition/Borders/NoBorder.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/Spectre.Console/Composition/Borders/NoBorder.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| namespace Spectre.Console.Composition | ||||
| { | ||||
|     internal sealed class NoBorder : Border | ||||
|     { | ||||
|         protected override string GetBoxPart(BorderPart part) | ||||
|         { | ||||
|             return " "; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -8,28 +8,28 @@ namespace Spectre.Console.Composition | ||||
|     public sealed class SquareBorder : Border | ||||
|     { | ||||
|         /// <inheritdoc/> | ||||
|         protected override char GetBoxPart(BorderPart part) | ||||
|         protected override string GetBoxPart(BorderPart part) | ||||
|         { | ||||
|             return part switch | ||||
|             { | ||||
|                 BorderPart.HeaderTopLeft => '┌', | ||||
|                 BorderPart.HeaderTop => '─', | ||||
|                 BorderPart.HeaderTopSeparator => '┬', | ||||
|                 BorderPart.HeaderTopRight => '┐', | ||||
|                 BorderPart.HeaderLeft => '│', | ||||
|                 BorderPart.HeaderSeparator => '│', | ||||
|                 BorderPart.HeaderRight => '│', | ||||
|                 BorderPart.HeaderBottomLeft => '├', | ||||
|                 BorderPart.HeaderBottom => '─', | ||||
|                 BorderPart.HeaderBottomSeparator => '┼', | ||||
|                 BorderPart.HeaderBottomRight => '┤', | ||||
|                 BorderPart.CellLeft => '│', | ||||
|                 BorderPart.CellSeparator => '│', | ||||
|                 BorderPart.ColumnRight => '│', | ||||
|                 BorderPart.FooterBottomLeft => '└', | ||||
|                 BorderPart.FooterBottom => '─', | ||||
|                 BorderPart.FooterBottomSeparator => '┴', | ||||
|                 BorderPart.FooterBottomRight => '┘', | ||||
|                 BorderPart.HeaderTopLeft => "┌", | ||||
|                 BorderPart.HeaderTop => "─", | ||||
|                 BorderPart.HeaderTopSeparator => "┬", | ||||
|                 BorderPart.HeaderTopRight => "┐", | ||||
|                 BorderPart.HeaderLeft => "│", | ||||
|                 BorderPart.HeaderSeparator => "│", | ||||
|                 BorderPart.HeaderRight => "│", | ||||
|                 BorderPart.HeaderBottomLeft => "├", | ||||
|                 BorderPart.HeaderBottom => "─", | ||||
|                 BorderPart.HeaderBottomSeparator => "┼", | ||||
|                 BorderPart.HeaderBottomRight => "┤", | ||||
|                 BorderPart.CellLeft => "│", | ||||
|                 BorderPart.CellSeparator => "│", | ||||
|                 BorderPart.ColumnRight => "│", | ||||
|                 BorderPart.FooterBottomLeft => "└", | ||||
|                 BorderPart.FooterBottom => "─", | ||||
|                 BorderPart.FooterBottomSeparator => "┴", | ||||
|                 BorderPart.FooterBottomRight => "┘", | ||||
|                 _ => throw new InvalidOperationException("Unknown box part."), | ||||
|             }; | ||||
|         } | ||||
|   | ||||
| @@ -15,6 +15,7 @@ namespace Spectre.Console | ||||
|         private readonly List<Text> _columns; | ||||
|         private readonly List<List<Text>> _rows; | ||||
|         private readonly Border _border; | ||||
|         private readonly BorderKind _borderKind; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Initializes a new instance of the <see cref="Table"/> class. | ||||
| @@ -25,6 +26,7 @@ namespace Spectre.Console | ||||
|             _columns = new List<Text>(); | ||||
|             _rows = new List<List<Text>>(); | ||||
|             _border = Border.GetBorder(border); | ||||
|             _borderKind = border; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
| @@ -104,8 +106,15 @@ namespace Spectre.Console | ||||
|         /// <inheritdoc/> | ||||
|         public IEnumerable<Segment> Render(Encoding encoding, int width) | ||||
|         { | ||||
|             var showBorder = _borderKind != BorderKind.None; | ||||
|             var hideBorder = _borderKind == BorderKind.None; | ||||
|  | ||||
|             var leftRightBorderWidth = _borderKind == BorderKind.None ? 0 : 2; | ||||
|             var columnPadding = _borderKind == BorderKind.None ? _columns.Count : _columns.Count * 2; | ||||
|             var separatorCount = _borderKind == BorderKind.None ? 0 : _columns.Count - 1; | ||||
|  | ||||
|             // Calculate the max width for each column. | ||||
|             var maxColumnWidth = (width - (2 + (_columns.Count * 2) + (_columns.Count - 1))) / _columns.Count; | ||||
|             var maxColumnWidth = (width - (leftRightBorderWidth + columnPadding + separatorCount)) / _columns.Count; | ||||
|             var columnWidths = _columns.Select(c => c.Measure(encoding, maxColumnWidth)).ToArray(); | ||||
|             for (var rowIndex = 0; rowIndex < _rows.Count; rowIndex++) | ||||
|             { | ||||
| @@ -120,7 +129,7 @@ namespace Spectre.Console | ||||
|             } | ||||
|  | ||||
|             // We now know the max width of each column, so let's recalculate the width. | ||||
|             width = columnWidths.Sum() + 2 + (_columns.Count * 2) + (_columns.Count - 1); | ||||
|             width = columnWidths.Sum() + leftRightBorderWidth + columnPadding + separatorCount; | ||||
|  | ||||
|             // Create the rows. | ||||
|             var rows = new List<List<Text>>(); | ||||
| @@ -133,9 +142,8 @@ namespace Spectre.Console | ||||
|             { | ||||
|                 var cellHeight = 1; | ||||
|  | ||||
|                 // Get the list of cells for the row. | ||||
|                 // Get the list of cells for the row and calculate the cell height. | ||||
|                 var cells = new List<List<SegmentLine>>(); | ||||
|  | ||||
|                 foreach (var (rowWidth, cell) in columnWidths.Zip(row, (f, s) => (f, s))) | ||||
|                 { | ||||
|                     var lines = Segment.SplitLines(cell.Render(encoding, rowWidth)); | ||||
| @@ -143,7 +151,8 @@ namespace Spectre.Console | ||||
|                     cells.Add(lines); | ||||
|                 } | ||||
|  | ||||
|                 if (firstRow) | ||||
|                 // Show top of header? | ||||
|                 if (firstRow && showBorder) | ||||
|                 { | ||||
|                     result.Add(new Segment(_border.GetPart(BorderPart.HeaderTopLeft))); | ||||
|                     foreach (var (columnIndex, _, lastColumn, columnWidth) in columnWidths.Enumerate()) | ||||
| @@ -171,31 +180,42 @@ namespace Spectre.Console | ||||
|                     var w00t = cells.Enumerate().ToArray(); | ||||
|                     foreach (var (cellIndex, firstCell, lastCell, cell) in w00t) | ||||
|                     { | ||||
|                         if (firstCell) | ||||
|                         if (firstCell && showBorder) | ||||
|                         { | ||||
|                             // Show left column edge | ||||
|                             result.Add(new Segment(_border.GetPart(BorderPart.CellLeft))); | ||||
|                         } | ||||
|  | ||||
|                         result.Add(new Segment(" ")); | ||||
|                         // Pad column on left side. | ||||
|                         if (showBorder) | ||||
|                         { | ||||
|                             result.Add(new Segment(" ")); | ||||
|                         } | ||||
|  | ||||
|                         // Add content | ||||
|                         result.AddRange(cell[cellRowIndex]); | ||||
|  | ||||
|                         // Pad cell right | ||||
|                         // Pad cell content right | ||||
|                         var length = cell[cellRowIndex].Sum(segment => segment.CellLength(encoding)); | ||||
|                         if (length < columnWidths[cellIndex]) | ||||
|                         { | ||||
|                             result.Add(new Segment(new string(' ', columnWidths[cellIndex] - length))); | ||||
|                         } | ||||
|  | ||||
|                         result.Add(new Segment(" ")); | ||||
|  | ||||
|                         if (lastCell) | ||||
|                         // Pad column on the right side | ||||
|                         if (showBorder || (hideBorder && !lastCell)) | ||||
|                         { | ||||
|                             // Separator | ||||
|                             result.Add(new Segment(" ")); | ||||
|                         } | ||||
|  | ||||
|                         if (lastCell && showBorder) | ||||
|                         { | ||||
|                             // Add right column edge | ||||
|                             result.Add(new Segment(_border.GetPart(BorderPart.ColumnRight))); | ||||
|                         } | ||||
|                         else | ||||
|                         else if (showBorder || (hideBorder && !lastCell)) | ||||
|                         { | ||||
|                             // Separator | ||||
|                             // Add column separator | ||||
|                             result.Add(new Segment(_border.GetPart(BorderPart.CellSeparator))); | ||||
|                         } | ||||
|                     } | ||||
| @@ -203,7 +223,8 @@ namespace Spectre.Console | ||||
|                     result.Add(Segment.LineBreak()); | ||||
|                 } | ||||
|  | ||||
|                 if (firstRow) | ||||
|                 // Show bottom of header? | ||||
|                 if (firstRow && showBorder) | ||||
|                 { | ||||
|                     result.Add(new Segment(_border.GetPart(BorderPart.HeaderBottomLeft))); | ||||
|                     foreach (var (columnIndex, first, lastColumn, columnWidth) in columnWidths.Enumerate()) | ||||
| @@ -222,7 +243,8 @@ namespace Spectre.Console | ||||
|                     result.Add(Segment.LineBreak()); | ||||
|                 } | ||||
|  | ||||
|                 if (lastRow) | ||||
|                 // Show bottom of footer? | ||||
|                 if (lastRow && showBorder) | ||||
|                 { | ||||
|                     result.Add(new Segment(_border.GetPart(BorderPart.FooterBottomLeft))); | ||||
|                     foreach (var (columnIndex, first, lastColumn, columnWidth) in columnWidths.Enumerate()) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user