Skip to content

Fix UTF-8 string length calculation in bar chart widget #4

@errordnk

Description

@errordnk

Problem

In src/ui/widgets/bar_chart.rs, app names containing multibyte UTF-8 characters (e.g. Cyrillic, Chinese, Japanese) are displayed incorrectly in the Top Apps by Bandwidth panel.

Two bugs in the label truncation/padding logic:

// BUG 1: .len() returns byte length, not character count
// For "яндекс": .len() == 12, but visible width == 6
if entry.label.len() > label_width {
    // BUG 2: slicing by byte index panics on multibyte char boundaries
    format!("{}…", &entry.label[..label_width - 1])
} else {
    // BUG 3: {:width$} pads by bytes, so multibyte strings get under-padded
    format!("{:width$}", entry.label, width = label_width)
}

Consequences

  • Cyrillic/CJK app names are never truncated even when they exceed label_width, so the bar and value columns get pushed out of frame
  • Slicing &entry.label[..label_width - 1] on a multibyte string can panic at runtime if the index falls in the middle of a UTF-8 sequence
  • The {:width$} padding formatter counts bytes, not characters, so short multibyte names receive less padding than ASCII names of the same visible length, misaligning all columns

Steps to reproduce

Run psnet on a system where any process name contains non-ASCII characters (common on Russian/CJK Windows installs — e.g. "Яндекс Браузер").

Fix

Replace byte-based operations with char-based ones:

let name = {
    let char_count = entry.label.chars().count();
    if char_count > label_width {
        let truncated: String = entry.label
            .chars()
            .take(label_width - 1)
            .collect();
        format!("{}…", truncated)
    } else {
        let pad = label_width - char_count;
        format!("{}{}", entry.label, " ".repeat(pad))
    }
};
  • .chars().count() — counts Unicode scalar values, not bytes
  • .chars().take(n).collect() — safe truncation that never splits a multibyte sequence
  • " ".repeat(pad) — correct column padding regardless of character width

Note: for full CJK support (wide characters that occupy 2 terminal columns) the unicode-width crate would be needed, but this fix already covers the common Cyrillic/Latin case correctly since those are all single-column characters.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions