diff --git a/ChangeLogs/2.1.0-ChangeLog.md b/ChangeLogs/2.1.0-ChangeLog.md new file mode 100644 index 0000000..50f4579 --- /dev/null +++ b/ChangeLogs/2.1.0-ChangeLog.md @@ -0,0 +1,44 @@ +# V2.1.0 + +## New Properties + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `ShowBorders` | `bool` | `true` | When `false`, the table is drawn without borders for a more minimalist style | + + +```csharp +using ConsoleTable.Text; + +// Setup the table +var table = new Table +{ + ShowBorders = false +}; + +// Set headers +table.SetHeaders("Name", "Age", "City"); + +// Add rows +table.AddRow("Alice Cooper", "30", "New York"); +table.AddRows(new string[][] +{ + new string[] { "Bob", "25", "Los Angeles" }, + new string[] { "Charlie Brown", "47", "Chicago" } +}); + +// Set footers +table.SetFooters("Total: 3", "Total Age: 102"); + +// Display the table +Console.WriteLine(table.ToTable()); +``` + +Output: +``` + Name Age City + Alice Cooper 30 New York + Bob 25 Los Angeles + Charlie Brown 47 Chicago + Total: 3 Total Age: 102 +``` diff --git a/ConsoleTable.Text.Examples/Program.cs b/ConsoleTable.Text.Examples/Program.cs index 2d18ed7..80c0249 100644 --- a/ConsoleTable.Text.Examples/Program.cs +++ b/ConsoleTable.Text.Examples/Program.cs @@ -4,6 +4,12 @@ class Program { static void Main(string[] args) { + Console.ForegroundColor = ConsoleColor.Black; + Console.BackgroundColor = ConsoleColor.White; + Console.Clear(); + Console.WriteLine(); + Console.WriteLine(); + WriteDefaultTable(); WriteDefaultTableWithProperties(); @@ -32,8 +38,12 @@ static void Main(string[] args) WriteTableFluent(); - WriteBigTable(); + WriteTableWithoutBorders(); + //WriteBigTable(); + + Console.WriteLine(); + Console.WriteLine(); Console.Read(); } @@ -78,7 +88,8 @@ private static void WriteDefaultTableWithProperties() new string[] { "Alice Cooper", "30", "New York" }, new string[] { "Bob", "25", "Los Angeles" }, new string[] { "Charlie Brown", "47", "Chicago" } - } + }, + Footers = new string[] { "Total: 3", "Total Age: 102" } }; Console.WriteLine(table.ToTable()); @@ -245,6 +256,36 @@ private static void WriteTableFluent() Console.WriteLine(); } + private static void WriteTableWithoutBorders() + { + Console.WriteLine(); + Console.WriteLine("Table without borders:"); + + // Setup the table + var table = new Table + { + ShowBorders = false + }; + + // Set headers + table.SetHeaders("Name", "Age", "City"); + + // Add rows + table.AddRow("Alice Cooper", "30", "New York"); + table.AddRows(new string[][] + { + new string[] { "Bob", "25", "Los Angeles" }, + new string[] { "Charlie Brown", "47", "Chicago" } + }); + + // Set footers + table.SetFooters("Total: 3", "Total Age: 102"); + + // Display the table + Console.WriteLine(table.ToTable()); + Console.WriteLine(); + } + private static void WriteBigTable() { Console.WriteLine(); diff --git a/ConsoleTable.Text/ConsoleTable.Text.csproj b/ConsoleTable.Text/ConsoleTable.Text.csproj index bb38db6..e2c001c 100644 --- a/ConsoleTable.Text/ConsoleTable.Text.csproj +++ b/ConsoleTable.Text/ConsoleTable.Text.csproj @@ -5,7 +5,7 @@ ConsoleTable.Text - 2.0.0 + 2.1.0 Bruno Van Thournout A library for creating a formatted string table with customizable headers, footers, rows and easy to use styling options. https://github.com/BrunoVT1992/ConsoleTable diff --git a/ConsoleTable.Text/Table.cs b/ConsoleTable.Text/Table.cs index 84a111c..6e26810 100644 --- a/ConsoleTable.Text/Table.cs +++ b/ConsoleTable.Text/Table.cs @@ -100,10 +100,10 @@ public bool HeaderTextAlignmentRight } } + private bool _rowTextAlignmentRight; /// /// Gets or sets a value indicating whether the row text is aligned to the right or left /// - private bool _rowTextAlignmentRight; public bool RowTextAlignmentRight { get => _rowTextAlignmentRight; @@ -114,10 +114,10 @@ public bool RowTextAlignmentRight } } + private bool _footerTextAlignmentRight; /// /// Gets or sets a value indicating whether the footer text is aligned to the right or left /// - private bool _footerTextAlignmentRight; public bool FooterTextAlignmentRight { get => _footerTextAlignmentRight; @@ -128,6 +128,20 @@ public bool FooterTextAlignmentRight } } + private bool _showBorders = true; + /// + /// Gets or sets a value indicating whether the table borders are visible. Default is true. + /// + public bool ShowBorders + { + get => _showBorders; + set + { + _showBorders = value; + ClearCache(); + } + } + /// /// Sets the headers of the table. Overwrites them each time. /// @@ -194,8 +208,6 @@ public Table ClearRows() return this; } - - /// /// Clears the cached generated table string /// @@ -238,10 +250,13 @@ public string ToTable() if (Headers?.Any() == true) { - formattedTable = CreateTopLine(maximumCellWidths, Headers.Count(), formattedTable); - topLineCreated = true; + if (ShowBorders) + { + formattedTable = CreateTopLine(maximumCellWidths, Headers.Count(), formattedTable); + topLineCreated = true; + } - formattedTable = CreateValueLine(maximumCellWidths, Headers, HeaderTextAlignmentRight, TableDrawing.VerticalLine, formattedTable); + formattedTable = CreateValueLine(maximumCellWidths, Headers, HeaderTextAlignmentRight, ShowBorders ? TableDrawing.VerticalLine : TableDrawing.EmptySpace, formattedTable); previousRow = Headers; @@ -249,17 +264,23 @@ public string ToTable() if (Rows?.Any() == true) { nextRow = Rows.First(); - formattedTable = CreateSeperatorLine(maximumCellWidths, previousRow.Count(), nextRow.Count(), TableDrawing.HorizontalHeaderLine, formattedTable); + if (ShowBorders) + { + formattedTable = CreateSeperatorLine(maximumCellWidths, previousRow.Count(), nextRow.Count(), TableDrawing.HorizontalHeaderLine, formattedTable); + } } else { - formattedTable = CreateBottomLine(maximumCellWidths, Headers.Count(), TableDrawing.HorizontalHeaderLine, formattedTable); + if (ShowBorders) + { + formattedTable = CreateBottomLine(maximumCellWidths, Headers.Count(), TableDrawing.HorizontalHeaderLine, formattedTable); + } } } if (Rows?.Any() == true) { - if (!topLineCreated) + if (!topLineCreated && ShowBorders) { formattedTable = CreateTopLine(maximumCellWidths, Rows.First().Count(), formattedTable); topLineCreated = true; @@ -272,7 +293,7 @@ public string ToTable() { var row = CleanupRow(Rows[i]); - formattedTable = CreateValueLine(maximumCellWidths, row, RowTextAlignmentRight, TableDrawing.VerticalLine, formattedTable); + formattedTable = CreateValueLine(maximumCellWidths, row, RowTextAlignmentRight, ShowBorders ? TableDrawing.VerticalLine : TableDrawing.EmptySpace, formattedTable); previousRow = row; @@ -280,13 +301,19 @@ public string ToTable() { nextRow = CleanupRow(Rows[rowIndex + 1]); - formattedTable = CreateSeperatorLine(maximumCellWidths, previousRow.Count(), nextRow.Count(), TableDrawing.HorizontalLine, formattedTable); + if (ShowBorders) + { + formattedTable = CreateSeperatorLine(maximumCellWidths, previousRow.Count(), nextRow.Count(), TableDrawing.HorizontalLine, formattedTable); + } } rowIndex++; } - formattedTable = CreateBottomLine(maximumCellWidths, previousRow.Count(), TableDrawing.HorizontalLine, formattedTable); + if (ShowBorders) + { + formattedTable = CreateBottomLine(maximumCellWidths, previousRow.Count(), TableDrawing.HorizontalLine, formattedTable); + } } if (Footers?.Any() == true) @@ -411,8 +438,16 @@ private StringBuilder CreateValueLine(int[] maximumCellWidths, string[] row, boo if (Padding > 0) paddingString = string.Concat(Enumerable.Repeat(' ', Padding)); - foreach (var column in row) + for (int i = 0; i < row.Length; i++) { + var column = row[i]; + + var leftVerticalLine = verticalLine; + if (i == 0 && !ShowBorders) + { + leftVerticalLine = TableDrawing.Empty; + } + var restWidth = maximumCellWidths[cellIndex]; if (Padding > 0) restWidth -= Padding * 2; @@ -420,13 +455,13 @@ private StringBuilder CreateValueLine(int[] maximumCellWidths, string[] row, boo var cellValue = alignRight ? column.PadLeft(restWidth, ' ') : column.PadRight(restWidth, ' '); if (cellIndex == 0 && cellIndex == lastCellIndex) - formattedTable.AppendLine(string.Format("{0}{1}{2}{3}{4}", verticalLine, paddingString, cellValue, paddingString, verticalLine)); + formattedTable.AppendLine(string.Format("{0}{1}{2}{3}{4}", leftVerticalLine, paddingString, cellValue, paddingString, verticalLine)); else if (cellIndex == 0) - formattedTable.Append(string.Format("{0}{1}{2}{3}", verticalLine, paddingString, cellValue, paddingString)); + formattedTable.Append(string.Format("{0}{1}{2}{3}", leftVerticalLine, paddingString, cellValue, paddingString)); else if (cellIndex == lastCellIndex) - formattedTable.AppendLine(string.Format("{0}{1}{2}{3}{4}", verticalLine, paddingString, cellValue, paddingString, verticalLine)); + formattedTable.AppendLine(string.Format("{0}{1}{2}{3}{4}", leftVerticalLine, paddingString, cellValue, paddingString, verticalLine)); else - formattedTable.Append(string.Format("{0}{1}{2}{3}", verticalLine, paddingString, cellValue, paddingString)); + formattedTable.Append(string.Format("{0}{1}{2}{3}", leftVerticalLine, paddingString, cellValue, paddingString)); cellIndex++; } diff --git a/ConsoleTable.Text/TableDrawing.cs b/ConsoleTable.Text/TableDrawing.cs index d729daf..c9f60d0 100644 --- a/ConsoleTable.Text/TableDrawing.cs +++ b/ConsoleTable.Text/TableDrawing.cs @@ -15,5 +15,6 @@ internal static class TableDrawing public const char HorizontalHeaderLine = '═'; public const string VerticalLine = "│"; public const string EmptySpace = " "; + public const string Empty = ""; } } \ No newline at end of file diff --git a/ConsoleTable.slnx b/ConsoleTable.slnx index b907c3e..7b05515 100644 --- a/ConsoleTable.slnx +++ b/ConsoleTable.slnx @@ -9,6 +9,7 @@ + diff --git a/README.md b/README.md index 87903ad..71bbbaf 100644 --- a/README.md +++ b/README.md @@ -5,14 +5,14 @@ A lightweight .NET library for creating beautifully formatted console tables wit ## Features - Create formatted tables as a string with styled headers, footers and rows -- Unicode box-drawing characters for clean borders +- Unicode box-drawing characters for clean borders (borders are optional and can be disabled if you want a minimalist style) - Automatic column width calculation - Configurable cell padding - Text alignment options (left/right) for headers, footers and rows - Easy clearing and reusing of tables - Simple and intuitive API - Optimized for performance -- Support for varying column counts across rows (each row can have its own number of cells). +- Support for varying column counts across rows (each row can have its own number of cells) ## Releases Check releases for the changelog here [https://github.com/BrunoVT1992/ConsoleTable/releases/](https://github.com/BrunoVT1992/ConsoleTable/releases/) @@ -92,6 +92,7 @@ Output: | `RowTextAlignmentRight` | `bool` | `false` | When `true`, row text is right-aligned otherwise left aligned | | `FooterTextAlignmentRight` | `bool` | `false` | When `true`, footer text is right-aligned otherwise left aligned | | `CachingEnabled` | `bool` | `true` | When `true`, the generated table string is cached when the ToTable method is called. Cache will be cleared on any property change or method call. | +| `ShowBorders` | `bool` | `true` | When `false`, the table is drawn without borders for a more minimalist style | ### Methods @@ -154,7 +155,12 @@ Output: using ConsoleTable.Text; // Setup the table -var table = new Table { HeaderTextAlignmentRight = true, RowTextAlignmentRight = true, FooterTextAlignmentRight = true }; +var table = new Table +{ + HeaderTextAlignmentRight = true, + RowTextAlignmentRight = true, + FooterTextAlignmentRight = true +}; // Set headers table.SetHeaders("Name", "Age", "City"); @@ -249,13 +255,51 @@ Output: Footer 1 Footer 2 ``` +### Table without borders + +```csharp +using ConsoleTable.Text; + +// Setup the table +var table = new Table +{ + ShowBorders = false +}; + +// Set headers +table.SetHeaders("Name", "Age", "City"); + +// Add rows +table.AddRow("Alice Cooper", "30", "New York"); +table.AddRows(new string[][] +{ + new string[] { "Bob", "25", "Los Angeles" }, + new string[] { "Charlie Brown", "47", "Chicago" } +}); + +// Set footers +table.SetFooters("Total: 3", "Total Age: 102"); + +// Display the table +Console.WriteLine(table.ToTable()); +``` + +Output: +``` + Name Age City + Alice Cooper 30 New York + Bob 25 Los Angeles + Charlie Brown 47 Chicago + Total: 3 Total Age: 102 +``` + ### Write a Table Fluent ```csharp using ConsoleTable.Text; - var tableString = new Table() +var tableString = new Table() .SetHeaders("Name", "Age", "City") .AddRow("Alice Cooper", "30", "New York") .AddRows( @@ -282,6 +326,27 @@ Output: Total: 3 Total Age: 102 ``` +## Using only public properties +If you want just a fast and easy setup using only properties. + +```csharp +using ConsoleTable.Text; + +var table = new Table +{ + Headers = new string[] { "Name", "Age", "City" }, + Rows = new List + { + new string[] { "Alice Cooper", "30", "New York" }, + new string[] { "Bob", "25", "Los Angeles" }, + new string[] { "Charlie Brown", "47", "Chicago" } + }, + Footers = new string[] { "Total: 3", "Total Age: 102" } +}; + +Console.WriteLine(table.ToTable()); +``` + ### Header only ```csharp @@ -305,7 +370,7 @@ Output: ```csharp using ConsoleTable.Text; - var table = new Table(); +var table = new Table(); for (int i = 1; i <= 5; i++) { diff --git a/Tests/ConsoleTable.Text.Tests/TableTests.cs b/Tests/ConsoleTable.Text.Tests/TableTests.cs index 25499be..2462fb6 100644 --- a/Tests/ConsoleTable.Text.Tests/TableTests.cs +++ b/Tests/ConsoleTable.Text.Tests/TableTests.cs @@ -537,6 +537,47 @@ public void FooterTextAlignRight_True_AlignsToDifferentPosition() Assert.Contains("F", resultRight); Assert.NotEqual(resultLeft, resultRight); } + + [Fact] + public void ShowBorders_DefaultValue_IsTrue() + { + var table = new Table(); + + Assert.True(table.ShowBorders); + } + + [Fact] + public void ShowBorders_False_RemovesBorderCharacters() + { + var table = new Table { ShowBorders = false }; + table.SetHeaders("Name", "Age"); + table.AddRow("John", "30"); + table.AddRow("Jane", "25"); + table.SetFooters("Footer1", "Footer2"); + + var result = table.ToTable(); + + // Should NOT contain border characters + Assert.DoesNotContain("│", result); // Vertical line + Assert.DoesNotContain("─", result); // Horizontal line + Assert.DoesNotContain("├", result); // Left joint + Assert.DoesNotContain("┤", result); // Right joint + Assert.DoesNotContain("┌", result); // Top left corner + Assert.DoesNotContain("┐", result); // Top right corner + Assert.DoesNotContain("└", result); // Bottom left corner + Assert.DoesNotContain("┘", result); // Bottom right corner + Assert.DoesNotContain("┼", result); // Middle joint + + // Should still contain the actual content + Assert.Contains("Name", result); + Assert.Contains("Age", result); + Assert.Contains("John", result); + Assert.Contains("30", result); + Assert.Contains("Jane", result); + Assert.Contains("25", result); + Assert.Contains("Footer1", result); + Assert.Contains("Footer2", result); + } #endregion #region Cache