feat: complete Rust port of claude-statusline

Port the entire 2236-line bash statusline script to Rust.
Implements all 25 sections, 3-phase layout engine (render, priority
drop, flex/justify), file-based caching with flock, 9-level terminal
width detection, trend sparklines, and deep-merge JSON config.

Release binary: 864K with LTO. Render time: <1ms warm.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Taylor Eernisse
2026-02-06 14:21:57 -05:00
commit b55d1aefd1
65 changed files with 12439 additions and 0 deletions

177
src/layout/mod.rs Normal file
View File

@@ -0,0 +1,177 @@
pub mod flex;
pub mod justify;
pub mod priority;
use crate::config::{Config, JustifyMode, LayoutValue};
use crate::section::{self, RenderContext, SectionOutput};
/// A section that survived priority drops and has rendered output.
pub struct ActiveSection {
pub id: String,
pub output: SectionOutput,
pub priority: u8,
pub is_spacer: bool,
pub is_flex: bool,
}
/// Resolve layout: preset lookup with optional responsive override.
pub fn resolve_layout(config: &Config, term_width: u16) -> Vec<Vec<String>> {
match &config.layout {
LayoutValue::Preset(name) => {
let effective = if config.global.responsive {
responsive_preset(term_width, &config.global.breakpoints)
} else {
name.as_str()
};
config
.presets
.get(effective)
.or_else(|| config.presets.get(name.as_str()))
.cloned()
.unwrap_or_else(|| vec![vec!["model".into(), "project".into()]])
}
LayoutValue::Custom(lines) => lines.clone(),
}
}
fn responsive_preset(width: u16, bp: &crate::config::Breakpoints) -> &'static str {
if width < bp.narrow {
"dense"
} else if width < bp.medium {
"standard"
} else {
"verbose"
}
}
/// Full render: resolve layout, render each line, join with newlines.
pub fn render_all(ctx: &RenderContext) -> String {
let layout = resolve_layout(ctx.config, ctx.term_width);
let separator = &ctx.config.global.separator;
let lines: Vec<String> = layout
.iter()
.filter_map(|line_ids| render_line(line_ids, ctx, separator))
.collect();
lines.join("\n")
}
/// Render a single layout line.
/// Three phases: render all -> priority drop -> flex/justify.
fn render_line(section_ids: &[String], ctx: &RenderContext, separator: &str) -> Option<String> {
// Phase 1: Render all sections, collect active ones
let mut active: Vec<ActiveSection> = Vec::new();
for id in section_ids {
if let Some(output) = section::render_section(id, ctx) {
if output.raw.is_empty() && !section::is_spacer(id) {
continue;
}
let (prio, is_flex) = section_meta(id, ctx.config);
active.push(ActiveSection {
id: id.clone(),
output,
priority: prio,
is_spacer: section::is_spacer(id),
is_flex,
});
}
}
if active.is_empty() || active.iter().all(|s| s.is_spacer) {
return None;
}
// Phase 2: Priority drop if overflowing
let mut active = priority::priority_drop(active, ctx.term_width, separator);
// Phase 3: Flex expand or justify
let line = if ctx.config.global.justify != JustifyMode::Left
&& !active.iter().any(|s| s.is_spacer)
&& active.len() > 1
{
justify::justify(
&active,
ctx.term_width,
separator,
ctx.config.global.justify,
)
} else {
flex::flex_expand(&mut active, ctx, separator);
assemble_left(&active, separator, ctx.color_enabled)
};
Some(line)
}
/// Left-aligned assembly with separator dimming and spacer suppression.
fn assemble_left(active: &[ActiveSection], separator: &str, color_enabled: bool) -> String {
let mut output = String::new();
let mut prev_is_spacer = false;
for (i, sec) in active.iter().enumerate() {
if i > 0 && !prev_is_spacer && !sec.is_spacer {
if color_enabled {
output.push_str(&format!(
"{}{separator}{}",
crate::color::DIM,
crate::color::RESET
));
} else {
output.push_str(separator);
}
}
output.push_str(&sec.output.ansi);
prev_is_spacer = sec.is_spacer;
}
output
}
/// Look up section priority and flex from config.
fn section_meta(id: &str, config: &Config) -> (u8, bool) {
if section::is_spacer(id) {
return (1, true);
}
macro_rules! meta_base {
($section:expr) => {
($section.priority, $section.flex)
};
}
macro_rules! meta_flat {
($section:expr) => {
($section.base.priority, $section.base.flex)
};
}
match id {
"model" => meta_base!(config.sections.model),
"provider" => meta_base!(config.sections.provider),
"project" => meta_flat!(config.sections.project),
"vcs" => meta_flat!(config.sections.vcs),
"beads" => meta_flat!(config.sections.beads),
"context_bar" => meta_flat!(config.sections.context_bar),
"context_usage" => meta_flat!(config.sections.context_usage),
"context_remaining" => meta_flat!(config.sections.context_remaining),
"tokens_raw" => meta_flat!(config.sections.tokens_raw),
"cache_efficiency" => meta_base!(config.sections.cache_efficiency),
"cost" => meta_flat!(config.sections.cost),
"cost_velocity" => meta_base!(config.sections.cost_velocity),
"token_velocity" => meta_base!(config.sections.token_velocity),
"cost_trend" => meta_flat!(config.sections.cost_trend),
"context_trend" => meta_flat!(config.sections.context_trend),
"lines_changed" => meta_base!(config.sections.lines_changed),
"duration" => meta_base!(config.sections.duration),
"tools" => meta_flat!(config.sections.tools),
"turns" => meta_flat!(config.sections.turns),
"load" => meta_flat!(config.sections.load),
"version" => meta_base!(config.sections.version),
"time" => meta_flat!(config.sections.time),
"output_style" => meta_base!(config.sections.output_style),
"hostname" => meta_base!(config.sections.hostname),
_ => (2, false), // custom sections default
}
}