fix: 4 bugs found during code review against PRD

- output_style: use MAGENTA color per PRD (was incorrectly DIM)
- vcs: pass project dir to jj exec (was None, causing wrong cwd)
- tools: singular "tool" when count is 1 (was always "tools")
- layout: wire up apply_formatting() in render pipeline (prefix,
  suffix, color override, pad, align were completely dead code)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Taylor Eernisse
2026-02-06 14:28:50 -05:00
parent b55d1aefd1
commit 9c24617642
4 changed files with 51 additions and 6 deletions

View File

@@ -2,7 +2,8 @@ pub mod flex;
pub mod justify; pub mod justify;
pub mod priority; pub mod priority;
use crate::config::{Config, JustifyMode, LayoutValue}; use crate::config::{Config, JustifyMode, LayoutValue, SectionBase};
use crate::format;
use crate::section::{self, RenderContext, SectionOutput}; use crate::section::{self, RenderContext, SectionOutput};
/// A section that survived priority drops and has rendered output. /// A section that survived priority drops and has rendered output.
@@ -64,11 +65,22 @@ fn render_line(section_ids: &[String], ctx: &RenderContext, separator: &str) ->
let mut active: Vec<ActiveSection> = Vec::new(); let mut active: Vec<ActiveSection> = Vec::new();
for id in section_ids { for id in section_ids {
if let Some(output) = section::render_section(id, ctx) { if let Some(mut output) = section::render_section(id, ctx) {
if output.raw.is_empty() && !section::is_spacer(id) { if output.raw.is_empty() && !section::is_spacer(id) {
continue; continue;
} }
// Apply per-section formatting (prefix, suffix, color override, pad, align)
if let Some(base) = section_base(id, ctx.config) {
format::apply_formatting(
&mut output.raw,
&mut output.ansi,
base,
ctx.theme,
&ctx.config.colors,
);
}
let (prio, is_flex) = section_meta(id, ctx.config); let (prio, is_flex) = section_meta(id, ctx.config);
active.push(ActiveSection { active.push(ActiveSection {
id: id.clone(), id: id.clone(),
@@ -175,3 +187,35 @@ fn section_meta(id: &str, config: &Config) -> (u8, bool) {
_ => (2, false), // custom sections default _ => (2, false), // custom sections default
} }
} }
/// Look up the SectionBase for a given section ID.
/// Returns None for spacers and unknown custom sections.
fn section_base<'a>(id: &str, config: &'a Config) -> Option<&'a SectionBase> {
match id {
"model" => Some(&config.sections.model),
"provider" => Some(&config.sections.provider),
"project" => Some(&config.sections.project.base),
"vcs" => Some(&config.sections.vcs.base),
"beads" => Some(&config.sections.beads.base),
"context_bar" => Some(&config.sections.context_bar.base),
"context_usage" => Some(&config.sections.context_usage.base),
"context_remaining" => Some(&config.sections.context_remaining.base),
"tokens_raw" => Some(&config.sections.tokens_raw.base),
"cache_efficiency" => Some(&config.sections.cache_efficiency),
"cost" => Some(&config.sections.cost.base),
"cost_velocity" => Some(&config.sections.cost_velocity),
"token_velocity" => Some(&config.sections.token_velocity),
"cost_trend" => Some(&config.sections.cost_trend.base),
"context_trend" => Some(&config.sections.context_trend.base),
"lines_changed" => Some(&config.sections.lines_changed),
"duration" => Some(&config.sections.duration),
"tools" => Some(&config.sections.tools.base),
"turns" => Some(&config.sections.turns.base),
"load" => Some(&config.sections.load.base),
"version" => Some(&config.sections.version),
"time" => Some(&config.sections.time.base),
"output_style" => Some(&config.sections.output_style),
"hostname" => Some(&config.sections.hostname),
_ => None,
}
}

View File

@@ -10,7 +10,7 @@ pub fn render(ctx: &RenderContext) -> Option<SectionOutput> {
let raw = style_name.to_string(); let raw = style_name.to_string();
let ansi = if ctx.color_enabled { let ansi = if ctx.color_enabled {
format!("{}{raw}{}", color::DIM, color::RESET) format!("{}{raw}{}", color::MAGENTA, color::RESET)
} else { } else {
raw.clone() raw.clone()
}; };

View File

@@ -22,7 +22,8 @@ pub fn render(ctx: &RenderContext) -> Option<SectionOutput> {
String::new() String::new()
}; };
let raw = format!("{count} tools{last}"); let label = if count == 1 { "tool" } else { "tools" };
let raw = format!("{count} {label}{last}");
let ansi = if ctx.color_enabled { let ansi = if ctx.color_enabled {
format!("{}{raw}{}", color::DIM, color::RESET) format!("{}{raw}{}", color::DIM, color::RESET)
} else { } else {

View File

@@ -128,7 +128,7 @@ fn render_git(
fn render_jj( fn render_jj(
ctx: &RenderContext, ctx: &RenderContext,
_dir: &str, dir: &str,
ttl: &crate::config::VcsTtl, ttl: &crate::config::VcsTtl,
glyphs: &crate::config::GlyphConfig, glyphs: &crate::config::GlyphConfig,
) -> Option<SectionOutput> { ) -> Option<SectionOutput> {
@@ -147,7 +147,7 @@ fn render_jj(
"if(bookmarks, bookmarks.join(\",\"), change_id.shortest(8))", "if(bookmarks, bookmarks.join(\",\"), change_id.shortest(8))",
"--color=never", "--color=never",
], ],
None, Some(dir),
timeout, timeout,
)?; )?;
ctx.cache.set("vcs_branch", &out); ctx.cache.set("vcs_branch", &out);