CLI приложения #10. Таблицы и рамки

Когда программа выводит больше трёх строк данных, их хочется как-то упорядочить. Можно реализовать это ручным подсчётом пробелов и строками вида PadRight(20). Но это некрасиво, муторно и до момента, когда данных становится много.

Spectre.Console предлагает готовые блоки. Начнём с таблицы:

var table = new Table();
table.AddColumn("Файл");
table.AddColumn("Размер");
table.AddColumn("Статус");

table.AddRow("config.json", "2 КБ", "[green]OK[/]");
table.AddRow("data.csv", "148 КБ", "[green]OK[/]");
table.AddRow("backup.zip", "—", "[red]не найден[/]");

AnsiConsole.Write(table);
Таблица Файл/Размер/Статус: config.json, data.csv, backup.zip

Вывод в виде таблицы

Ширина колонок подбирается сама, разметка внутри ячеек работает. Дальше — настройки внешнего вида:

table.Border = TableBorder.Rounded;      // скруглённые углы
table.Title = new TableTitle("Проверка");
table.Columns[1].RightAligned();          // числа лучше по правому краю
table.Expand();                           // растянуть на всю ширину окна
Растянутая таблица с заголовком Проверка

Таблица с заголовком

Вариантов рамок много: Ascii для совместимости со старыми терминалами, Markdown — чтобы вывод можно было вставить прямо в README, None — если рамка не нужна.

Для одиночного сообщения, которое надо выделить, есть панель:

var panel = new Panel("Конфигурация загружена из ~/.myapp/config.json")
{
    Header = new PanelHeader("Настройки"),
    Border = BoxBorder.Rounded,
    Padding = new Padding(1, 0)
};

AnsiConsole.Write(panel);

Разделить вывод на смысловые части помогает линейка:

AnsiConsole.Write(new Rule("[yellow]Этап 1: проверка[/]").LeftJustified());

Она рисует горизонтальную черту во всю ширину с заголовком внутри. Незаменимая штука, когда программа выполняет несколько этапов подряд.

Если данные иерархические, вместо таблицы берём дерево:

var tree = new Tree("Проект");
var src = tree.AddNode("src");
src.AddNode("Program.cs");
src.AddNode("Commands");
tree.AddNode("README.md");

AnsiConsole.Write(tree);
Панель Настройки, линейка Этап 1 и дерево Проект

Блок, разделитель (линейка) и дерево

Важно!
Помните про шестой пост: всё это — оформление, а не данные. Если пользователь перенаправит вывод в файл, таблица попадёт туда вместе с рамками, и разобрать её автоматически будет невозможно. Что с этим делать — тема отдельного поста. Чуть позже.

Ещё один здравый совет: не превращайте вывод в новогоднюю ёлку. Рамка вокруг каждой строчки утомляет быстрее, чем помогает. Таблицы — для табличных данных, панель — для одного важного сообщения, линейка — для разделения этапов. Всё остальное прекрасно живёт обычным текстом.

Приложение научилось красиво показывать данные человеку. Осталось научить его не делать этого, когда человека нет. В следующем посте разберёмся, как одна и та же программа обслуживает и живого пользователя, и скрипт.