feat(core): responsive startup logo with adaptive layout#11413
Conversation
Redesigns the Nethermind startup banner so it scales with terminal width and stays readable on light and dark themes: - Picks one of three tiers based on Console.WindowWidth: full (glyph + figlet wordmark + URL), glyph + URL, or a one-line text fallback for very narrow terminals or no-TTY contexts. - Switches the wordmark from white-on-default to dimmed (�[2m) so it renders correctly on light terminals (e.g. default Docker tty), instead of being nearly invisible. - Centers each piece of the logo and the dividers within a single left-aligned block capped at the "Initialization Completed" separator width, so the whole screen reads as one column rather than floating in the middle of wide terminals.
|
Claude finished @stdevMac's task in 4m 40s —— View job PR Review —
|
| private const string SeparatorTitle = " Initialization Completed "; | ||
|
|
||
| // Visible widths used to compute centered padding at runtime. | ||
| private const int GlyphWidth = 47; |
There was a problem hiding this comment.
Medium — GlyphWidth constant is wrong; glyph line wraps at the boundary width
GlyphWidth = 47 does not match the actual widest glyph line. Counting the visible characters in _glyphLines:
- All lines except index 4 are 46 visible chars.
- Line index 4 (
" ------ - "+"~~~ ") is 50 visible chars: 39 + 11.
Since GlyphLogoMinWidth = 50, the glyph mode activates exactly when width == 50. At that point:
LeadingPad(50, 47) → blockWidth=50, innerPad=(50-47)/2=1 → " "
" " + <50-char glyph> = 51 chars on a 50-col terminal → wraps
Same at width = 51 (pad=2, total=52 > 51 → wraps). The author tested 40 and 60 but not 50–51.
Fix: Change GlyphWidth to 50 so centering arithmetic uses the true max line width. At width=50 this yields pad=0 (left-aligned, no overflow); at width=52+ centering works correctly.
| private const int GlyphWidth = 47; | |
| private const int GlyphWidth = 50; |
| private static int GetTerminalWidth() | ||
| { | ||
| try |
There was a problem hiding this comment.
Medium — bare catch swallows all exceptions
Console.WindowWidth throws IOException when stdout is not a TTY (as the comment correctly describes). Catching every exception type — including OutOfMemoryException, InvalidOperationException, unexpected runtime faults — makes bugs invisible.
Per robustness rules: "Never swallow exceptions in an empty catch block — at minimum log the exception."
Fix: Narrow the catch to IOException (the documented throw source) so unexpected exceptions still surface:
| private static int GetTerminalWidth() | |
| { | |
| try | |
| private static int GetTerminalWidth() | |
| { | |
| try | |
| { | |
| int w = Console.WindowWidth; | |
| return w > 0 ? w : SeparatorMaxWidth; | |
| } | |
| catch (IOException) | |
| { | |
| return SeparatorMaxWidth; | |
| } | |
| } |
Changes
Redesigns the Nethermind startup banner so it scales with terminal width and stays readable on both light and dark themes.
Console.WindowWidth:bigfiglet wordmark + URL�[37m) to dimmed (�[2m) so it renders correctly on light terminals such as the default Docker tty, instead of being nearly invisible.Types of changes
What types of changes does your code introduce?
Testing
Requires testing
Notes on testing
Verified visually at terminal widths of 40, 60, 80, and 100 cols, plus the no-TTY (redirected stdout) path. Behavior is purely formatting of the startup banner; no functional surface is affected.
Documentation
Requires documentation update
Requires explanation in Release Notes