Во-первых, я пробовал использовать множество библиотек, и ни одна из них, похоже, не работала должным образом, я тоже установил ширину терминала вручную, и текст все тот же, он не в центре терминала, кто-нибудь, что мне следует сделать?
ОБС: Я обнаружил, это из-за цветов, но как напечатать по центру и с цветами? (без цветов все идет правильно, вот как я обнаружил)
fn print_centered(content: &str) {
let term_size = crossterm::terminal::size();
let term_width = term_size.unwrap_or((80, 24)).0 as usize;
println!("{: ^term_width$}", content);
}
Я пробовал вручную и с большим количеством ящиков, но не отцентрировал содержимое должным образом, как ожидалось.
Размер терминала указан правильно, поскольку я проверял его вручную, но при печати текста он не находится в центре, как вы можете видеть на изображении.
Если вы также печатаете цветовые коды ANSI, они могут смещать текст относительно центра, если они не симметричны вокруг текста, как и символы Юникода с несколькими кодовыми точками.
вот и все, но как мне распечатать его в центре цветами?
Трудно сказать по изображению, но код кажется очень разумным. Я бы, вероятно, заменил пробел каким-нибудь печатным символом, например. println!("{:~^term_width$}", content); а потом посчитайте. Сколько всего символов напечатано? Соответствует ли это выводу tput cols?
я думаю, он не соответствует term_width из-за цветов
@mi66mc: Понятно, в этом есть смысл. Строка формата Rust выдаст вам term_width символы Юникода, независимо от их отображаемого размера. Если вы включите escape-последовательности Ansi в content (которые состоят из нескольких символов, но не отображаются), отображаемая длина будет слишком короткой. Вы можете использовать такую библиотеку, как ansi parser, для перебора content и определения фактической длины текста или, в качестве альтернативы, просто определить длину перед добавлением escape-символов ansii.
Если вы нашли ответ, пожалуйста, опубликуйте его, ведь собрать кучу пар QA — это весь смысл Stack Overflow.

На решение в целом намекнули в комментариях. Итак, это кульминация всего этого, а также фактическое решение.
Как вы уже поняли, проблема в том, что стандартное форматирование заливки/выравнивания основано на символах. Таким образом, встраивание цветовых кодов ANSI в строку считается символами.
Это можно наблюдать с помощью следующего кода:
let width = 25;
let text = "Hello World";
let text2 = format!("\x1b[94m{}\x1b[39m", text);
println!("{:-^width$}", "");
println!("{:-^width$}", text);
println!("{:-^width$}", text2);
println!();
println!("{} characters", text.chars().count());
println!("{} characters", text2.chars().count());
Какие выходы:

Использование изображения, поскольку вывод цветной.
Простой обходной путь — использовать контейнер консоли , который предоставляет различные утилиты для измерения текста, заполнения, усечения и т. д. При учете кодов ANSI:
Вы даже можете использовать Term . size(), чтобы получить ширину терминала.
Чтобы центрировать строку, содержащую коды ANSI, вам следует использовать pad_str() :
use console::{pad_str, Alignment};
let width = 25;
let text = "Hello World";
let text2 = format!("\x1b[94m{}\x1b[39m", text);
let text = pad_str(text, width, Alignment::Center, None);
let text2 = pad_str(&text2, width, Alignment::Center, None);
println!("{:-^width$}", "");
println!("{text}");
println!("{text2}");
println!("{:-^width$}", "");
Какие выходы:

Опять же, pad_str() не ломается text, даже если он усечен. Например, давайте установим width на 6 и будем использовать … (многоточие) для усечения.
use console::{pad_str, Alignment};
const ELLIPSIS: &str = "\u{2026}";
let width = 6;
let text = "Hello World";
let text2 = format!("\x1b[94m{}\x1b[39m", text);
let text = pad_str(text, width, Alignment::Center, Some(ELLIPSIS));
let text2 = pad_str(&text2, width, Alignment::Center, Some(ELLIPSIS));
println!("{:-^width$}", "");
println!("{text}");
println!("{text2}");
println!("{:-^width$}", "");
Что правильно выводит:

В чем ваша проблема: 1. Размер терминала указан неправильно; или 2. текст не центрирован, несмотря на правильный размер?