Skip to content

Style options aren't format-expanded. Silently falls back to bright-green. #372

@Gerrrt

Description

@Gerrrt

Summary

status-left, status-right, and the window-status formats are run through expand_format before being sent to the client, so #{...} references resolve correctly.

The style options (status-style, pane-border-style, pane-active-border-style, message-style, mode-style, window-status-separator, window-status) are not expanded; they're forwarded verbatim to the color parser.

A #{@my_colour} reference in any of them therefore fails to parse as a color, and status-style specifically falls back to a hard-coded Color::Green, painting the empty region of the status bar bright green.

Repro

set -g @bg "#292e42"
set -g status-style "bg=#{@bg}"

Expected:

  • status bar background is #292e42.

Actual:

  • the bar's empty/gap region renders bright green.

set -g status-style "bg=#292e42" works, confirming the value is fine and the expansion step is what's missing.

The same unexpanded-ref problem affects pane-border-style/pane-active-border-style (borders render with the wrong/failed color) and the other style options, though only status-style produces the dramatic green because of its fallback default.

Root cause

Server — src/server/mod.rs: status_left/status_right are expanded before being serialized…

let sl_expanded = json_escape_string(&expand_format(&app.status_left, &app));   // :1567
let sr_expanded = json_escape_string(&expand_format(&app.status_right, &app));  // :1568

…but status_style and pane-border are sent raw:

cached_status_style = app.status_style.clone();                 // :1558  (no expand_format)
let ss_escaped = json_escape_string(&cached_status_style);      // :1566
let pbs_escaped  = json_escape_string(&app.pane_border_style);        // :1569 (raw)
let pabs_escaped = json_escape_string(&app.pane_active_border_style); // :1570 (raw)

They're also stored raw at set-time (src/server/options.rs:340), so the #{...} survives all the way to the client.

Client — src/client.rs:4369-4375 parses that raw string:

let (fg, bg, bold) = parse_tmux_style_components(ss);   // ss == "bg=#{@bg}"
status_fg = fg.unwrap_or(Color::Black);
status_bg = bg.unwrap_or(Color::Green);                 // ← bright-green fallback

parse_tmux_style_components (src/style.rs:115-132) calls parse_tmux_color("#{@bg}"), which returns Nonestatus_bg defaults to Color::Green (also the init value at src/client.rs:1272).

expand_format does know how to resolve these refs (src/format.rs:843-844 looks @-prefixed names up in app.user_options) — it's simply never called on the style options.

Suggested fix

  1. Primary: run expand_format on the style options before sending them to the client, exactly as status_left/status_right already do — covering status_style, pane_border_style, pane_active_border_style, message_style, mode_style, window_status_separator, and the window-status styles. (Alternatively, expand at set-option time, but doing it at send time matches the existing status_left/right handling and stays correct if a @var changes at runtime.)

  2. Secondary: change the bg.unwrap_or(Color::Green) fallback (client.rs:4373, and the 1272 initializer) to Color::Reset so any future parse failure is invisible (terminal default) rather than alarming bright green.

Environment

psmux v3.3.5 (current Cargo.toml).

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