Albatross.Text.Table
A .NET library for rendering collections as formatted text tables with automatic column width adjustment and customizable formatting.
Installation
dotnet add package Albatross.Text.Table
Quick Start
using Albatross.Text.Table;
public record Product(int Id, string Name, decimal Price);
var products = new List<Product> {
new(1, "Laptop", 999.99m),
new(2, "Mouse", 25.50m),
new(3, "Keyboard", 75.00m)
};
// Print table with auto-discovered columns
products.StringTable().Print(Console.Out);
Output:
Id Name Price
-- -------- ------
1 Laptop 999.99
2 Mouse 25.5
3 Keyboard 75
------------------
TableOptions Configuration
Building Columns by Reflection
var options = new TableOptions<Product>()
.BuildColumnsByReflection()
.Cast<Product>();
products.StringTable(options).Print(Console.Out);
Manual Column Selection
var options = new TableOptions<Product>()
.SetColumn(x => x.Name)
.SetColumn(x => x.Price);
products.StringTable(options).Print(Console.Out);
Output:
Name Price
-------- ------
Laptop 999.99
Mouse 25.5
Keyboard 75
--------------
Custom Headers
var options = new TableOptions<Product>()
.BuildColumnsByReflection()
.Cast<Product>()
.ColumnHeader(x => x.Id, "#")
.ColumnHeader(x => x.Name, "Product Name")
.ColumnHeader(x => x.Price, "Unit Price");
Column Ordering
Lower order values appear first. Default order is based on property declaration.
var options = new TableOptions<Product>()
.BuildColumnsByReflection()
.Cast<Product>()
.ColumnOrder(x => x.Price, -1) // Move Price to first
.ColumnOrder(x => x.Name, 0) // Name second
.ColumnOrder(x => x.Id, 1); // Id last
Ignoring Columns
var options = new TableOptions<Product>()
.BuildColumnsByReflection()
.Cast<Product>()
.Ignore(x => x.Id); // Remove Id column
Value Formatting
var options = new TableOptions<Product>()
.BuildColumnsByReflection()
.Cast<Product>()
.Format(x => x.Price, "C2"); // Currency format: $999.99
Custom Value Extraction
var options = new TableOptions<Product>()
.BuildColumnsByReflection()
.Cast<Product>()
.SetColumn(x => x.Name, product => product.Name.ToUpper());
Custom Formatter with TextValue
var options = new TableOptions<Product>()
.BuildColumnsByReflection()
.Cast<Product>()
.Format(x => x.Price, (product, value) =>
new TextValue(((decimal)value!).ToString("C2")));
TableOptionFactory
Thread-safe singleton for registering and reusing table configurations globally.
Registering Options
var options = new TableOptions<Product>()
.BuildColumnsByReflection()
.Cast<Product>()
.Format(x => x.Price, "C2")
.Ignore(x => x.Id);
// Register globally
TableOptionFactory.Instance.Register(options);
// Now all calls use registered options automatically
products.StringTable().Print(Console.Out);
Retrieving Options
// Get registered options (or auto-create default)
var options = TableOptionFactory.Instance.Get<Product>();
StringTable
The core class for storing and rendering tabular data.
Creating from Headers
var table = new StringTable("Name", "Age", "City");
table.AddRow("John", "30", "Boston");
table.AddRow("Jane", "25", "Seattle");
table.Print(Console.Out);
Width Adjustment
Automatically reduces column widths to fit within a maximum total width.
var table = products.StringTable();
table.AdjustColumnWidth(60); // Fit in 60 characters
table.Print(Console.Out);
Column Minimum Width
Set minimum width to prevent columns from being truncated too much.
var table = products.StringTable()
.MinWidth(col => col.Name == "Name", 20) // Name at least 20 chars
.MinWidth(col => col.Name == "Price", 10); // Price at least 10 chars
table.AdjustColumnWidth(50);
table.Print(Console.Out);
Right Alignment
var table = products.StringTable()
.AlignRight(col => col.Name == "Price")
.AlignRight(col => col.Name == "Id");
table.Print(Console.Out);
Filtering Columns
var table = products.StringTable()
.FilterColumns("Name", "Price"); // Only show Name and Price
table.Print(Console.Out);
Filtering Rows
var table = products.StringTable()
.FilterRows("Price", value => decimal.Parse(value) > 50);
table.Print(Console.Out);
Print Options
table.Print(
Console.Out,
printHeader: true, // Show column headers
printFirstLineSeparator: true, // Line after header
printLastLineSeparator: true // Line after data
);
Dictionary Tables
var dict = new Dictionary<string, object> {
{ "Name", "John" },
{ "Age", 30 },
{ "City", "Boston" }
};
dict.StringTable().Print(Console.Out);
Output:
Key Value
---- ------
Name John
Age 30
City Boston
-----------
Markdown Export
using var writer = new StringWriter();
products.MarkdownTable(writer);
Console.WriteLine(writer.ToString());
Output:
Id|Name|Price
-|-|-
1|Laptop|999.99
2|Mouse|25.5
3|Keyboard|75
With custom options:
var options = new TableOptions<Product>()
.SetColumn(x => x.Name)
.SetColumn(x => x.Price);
products.MarkdownTable(writer, options);
Aligning Multiple Tables
When displaying multiple tables, align their columns for consistent formatting.
AlignFirst
Align all tables to match the first table's column widths.
var tables = new[] {
products1.StringTable(),
products2.StringTable(),
products3.StringTable()
};
tables.AlignFirst();
foreach (var table in tables) {
table.Print(Console.Out);
}
AlignAll
Use the maximum width across all tables for each column.
tables.AlignAll();
API Reference
TableOptions<T>
| Method | Description |
|---|---|
BuildColumnsByReflection() |
Auto-discover columns from properties |
Cast<T>() |
Convert to typed options for fluent API |
SetColumn(expression) |
Add column by property expression |
SetColumn(expression, getValue) |
Add column with custom value getter |
Ignore(expression) |
Remove column |
ColumnHeader(expression, header) |
Set custom header text |
ColumnOrder(expression, order) |
Set column display order |
Format(expression, format) |
Apply .NET format string |
Format(expression, formatter) |
Apply custom formatter |
PrintHeader(bool) |
Control header visibility |
PrintFirstLineSeparator(bool) |
Control header separator |
PrintLastLineSeparator(bool) |
Control footer separator |
StringTable
| Method | Description |
|---|---|
AddRow(values) |
Add data row |
Print(writer) |
Output to TextWriter |
AdjustColumnWidth(maxWidth) |
Fit table within width |
FilterColumns(columns) |
Show only specified columns |
FilterRows(column, predicate) |
Filter rows by value |
StringTableExtensions
| Method | Description |
|---|---|
StringTable() |
Create table from collection |
StringTable(options) |
Create with custom options |
MinWidth(predicate, width) |
Set column minimum width |
AlignRight(predicate) |
Right-align columns |
SetWidthLimit(width) |
Adjust to fit width |
PrintConsole(writer, maxWidth) |
Print with width limit |
TableOptionFactory
| Method | Description |
|---|---|
Instance |
Singleton instance |
Register(options) |
Register configuration |
Get<T>() |
Get or create configuration |
TryGet<T>(out options) |
Try to get existing configuration |