Search code examples
rustrust-cargocentering

How can I print a content in the middle of the screen in Rust?


Fisrtly I tried with a lot of libs and none of them seemed to work properly, i put the terminal width manually too and the text is all the same thing, it's not in the center of the terminal, does somebody what should I make?

OBS: I discovered, it's because of the colors, but how can i print it in the center and with colors? (without colors it goes right, thats how i discovered)

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);
}

enter image description here

enter image description here

I tried manually and with a lot of crates and didn't center the content properly as expected.


Solution

  • The solution have overall been hinted at in the comments. So this is the culmination of that, along with an actual solution.

    As you already figured out, the issue is that the standard fill/alignment formatting, is based on characters. While embedding ANSI color codes into a string is thus counted as characters.

    This is observable using the following code:

    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());
    

    Which outputs:

    Using an image, since the output is colored.


    An easy workaround, is to use the console crate, which provides various utilities for measuring text, padding, truncating etc. While accounting for ANSI codes:

    You can even use Term.size() to get the terminal width.

    To center a string containing ANSI codes, then you'd specifically use 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$}", "");
    

    Which outputs:


    Again, pad_str() does not break text, even if it is truncated. For instance, let's set the width to 6 and use (ellipsis) for truncation.

    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$}", "");
    

    Which correctly outputs: