Skip to content

fix(ui): stabilize local header metric row width to prevent jitter (#170)#171

Merged
inureyes merged 3 commits into
mainfrom
fix/issue-170-stabilize-local-header-width
Apr 10, 2026
Merged

fix(ui): stabilize local header metric row width to prevent jitter (#170)#171
inureyes merged 3 commits into
mainfrom
fix/issue-170-stabilize-local-header-width

Conversation

@inureyes

Copy link
Copy Markdown
Member

Summary

  • Right-align CPU/GPU percentage values in a 5-char numeric field → consistent 6-column string (" 0.0%" through "100.0%")
  • Right-align temperature values in a 3-char numeric field → consistent 5-column string (" 0°C" through "999°C")
  • Right-align power values in a 5-char numeric field → consistent 6-char string (" 0.0W" through "999.9W")
  • Pad the RAM used portion to the same digit-width as total so the separator / stays in a fixed column (e.g. always " 0/16GB" through "16/16GB")

Test plan

  • cargo test -p all-smi passes — updated existing assertions and added test_format_pct_fixed_width and test_format_temp_fixed_display_width to assert stable byte-lengths across digit boundaries
  • cargo clippy clean — no warnings
  • cargo fmt --check clean — formatting unchanged
  • Visual verification: run ./target/release/all-smi view in local mode and confirm the metrics row does not shift left/right as values cross 9→10 or 99→100 boundaries

Closes #170

Use fixed-width formatted fields for CPU/GPU percentage, temperature,
power, and RAM values in the local-mode header metrics row. Each value
is right-aligned within a constant-width field so that digit-boundary
transitions (e.g. 9.9%→10.0%) no longer shift neighboring segments.

Closes #170
@inureyes inureyes added type:bug Something isn't working priority:medium Medium priority issue mode:local Local mode related mode:view View mode related labels Apr 10, 2026
@inureyes

Copy link
Copy Markdown
Member Author

Security & Performance Review

Reviewer: Automated analysis
Scope: src/ui/local_header.rs (40 additions, 12 deletions)
Result: No issues found

Security Analysis

No security concerns. This PR modifies only format strings for TUI display output. There are no changes to:

  • External input parsing or user-supplied data handling
  • Network I/O, file I/O, or system calls
  • Authentication, authorization, or credential handling
  • Command execution or shell interaction
  • Dependencies or unsafe code

The formatting functions (format_pct, format_temp, power formatting) operate on hardware-sourced numeric values (f64, u32) that are never user-controllable. The output goes to a terminal buffer (crossterm::queue!), not to any persistent storage or network endpoint.

Performance Analysis

No performance concerns. The changes are strictly cosmetic adjustments to format!() macro calls:

  • format_pct: One format! call per render tick per metric (CPU%, GPU%). The addition of {v:>5.1} right-alignment padding has negligible cost -- std::fmt handles width padding internally without additional allocation beyond what the original {v:.1} already required.

  • format_temp: Same analysis -- {v:>3.0} vs {v:.0} is equivalent in cost.

  • draw_power_sparkline: {power_watts:>5.1}W -- same analysis.

  • draw_ram_sparkline: The new code computes total_str once and uses its .len() for the dynamic width. This adds one extra format! call for total_str, but it is a trivial integer-to-string conversion that occurs once per render tick. No measurable impact.

None of these paths are hot loops. They execute once per TUI refresh cycle (typically every 1-6 seconds depending on configuration).

Edge Case Note

The fixed-width fields will overflow their padding if values exceed the field width (e.g., power over 999.9W, temperature over 999C). This is acceptable because:

  1. These are local machine metrics, not aggregated cluster values
  2. No real hardware produces temperatures above 999C or local power above 999.9W
  3. Rust's format! gracefully expands the field (no truncation, no panic), so the only consequence would be the same jitter the PR is fixing -- which only manifests for physically impossible values

Tests

All 12 local_header tests pass, including the two new tests (test_format_pct_fixed_width, test_format_temp_fixed_display_width) that assert stable display widths across digit boundaries. Clippy and cargo fmt --check are clean.

Verdict

Approved -- no changes needed.

@inureyes

Copy link
Copy Markdown
Member Author

Implementation Review Summary

Intent

Stabilize the local-mode header metric row width by using fixed-width formatted fields for CPU%, GPU%, temperature, power, and RAM values, preventing horizontal jitter when values cross digit boundaries.

Findings Addressed

None required -- the implementation is correct and complete as submitted.

Remaining Items

None.

Verification

  • All stated requirements implemented
  • No placeholder/mock code remaining
  • Integrated into project code flow
  • Project conventions followed
  • Existing modules reused where applicable
  • No unintended structural changes
  • Tests pass (all 732 tests pass, 0 failures)

Review Details

Correctness: All four formatting changes produce stable display widths across digit boundaries:

  • format_pct(): right-aligned 5-char numeric + % = 6 display columns for all values 0.0 through 100.0. The N/A case is also padded to 6 columns.
  • format_temp(): right-aligned 3-char numeric + °C = 5 display columns for all values 0 through 999. The ° character is 2 bytes in UTF-8 but 1 display column, and the test correctly uses exact string comparison rather than byte-length comparison to verify.
  • Power: right-aligned 5-char numeric + W = 6 display columns for values 0.0 through 999.9.
  • RAM: used value padded to match total value digit width, keeping the / separator fixed.

Test coverage: Two new tests (test_format_pct_fixed_width and test_format_temp_fixed_display_width) specifically validate width stability across digit boundaries. Existing tests updated with correct expected values. All 12 local_header tests pass.

Convention consistency: The right-aligned fixed-width format specifiers ({:>N.M}) are consistent with the existing patterns used throughout the UI code (e.g., widgets.rs, chassis_renderer.rs, memory_renderer.rs).

Edge case note: Power values above 999.9W would exceed the 5-char field width, but this is acceptable for the local header context (single-machine monitoring). The dashboard mode handles multi-kilowatt aggregation separately with kW formatting.

Quality checks: cargo clippy clean, cargo fmt --check clean.

… header

Adds test_format_power_fixed_width and test_format_ram_fixed_separator_position
to cover the inline formatting logic in draw_power_sparkline and draw_ram_sparkline,
verifying that digit-boundary crossings do not shift column positions.
Use captured variables directly in format! strings per Rust 1.58+
style required by the clippy -D warnings configuration.
@inureyes

Copy link
Copy Markdown
Member Author

PR Finalization Complete

Summary

  • Tests: Added 2 new tests — test_format_power_fixed_width and test_format_ram_fixed_separator_position — covering the inline formatting logic in draw_power_sparkline and draw_ram_sparkline. The RAM test also caught a subtle point: used is padded to the digit-width of total (not to a fixed constant), so " 0/16GB" rather than "0/16GB". All 14 module tests pass.
  • Documentation: No changes needed — existing doc comments on the formatting helpers and module-level doc accurately describe the behavior.
  • Lint/Format: Fixed one clippy::uninlined_format_args violation introduced by the new tests (format argument inlined per Rust 1.58+ style).

All checks passing. Ready for merge.

@inureyes inureyes added the status:done Completed label Apr 10, 2026
@inureyes inureyes merged commit 26f68d0 into main Apr 10, 2026
2 checks passed
@inureyes inureyes deleted the fix/issue-170-stabilize-local-header-width branch April 10, 2026 08:23
@inureyes inureyes self-assigned this Apr 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mode:local Local mode related mode:view View mode related priority:medium Medium priority issue status:done Completed type:bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(ui): stabilize local header metric row width to prevent left-right jitter

1 participant