Skip to main content

linesmith_core/segments/
output_style.rs

1//! Output style segment: renders Claude Code's active `output_style.name`
2//! (e.g. "default", "concise", "explanatory"). Hidden when the payload
3//! doesn't carry it. Opt-in: not in the default segment list.
4
5use super::{RenderContext, RenderResult, RenderedSegment, Segment, SegmentDefaults};
6use crate::data_context::DataContext;
7use crate::theme::Role;
8
9pub struct OutputStyleSegment;
10
11/// Informational; drops before cost (192), kept past rate-limit (96).
12const PRIORITY: u8 = 160;
13
14impl Segment for OutputStyleSegment {
15    fn render(&self, ctx: &DataContext, _rc: &RenderContext) -> RenderResult {
16        let Some(style) = ctx.status.output_style.as_ref() else {
17            crate::lsm_debug!("output_style: status.output_style absent; hiding");
18            return Ok(None);
19        };
20        Ok(Some(
21            RenderedSegment::new(style.name.as_str()).with_role(Role::Muted),
22        ))
23    }
24
25    fn defaults(&self) -> SegmentDefaults {
26        SegmentDefaults::with_priority(PRIORITY)
27    }
28}
29
30#[cfg(test)]
31mod tests {
32    use super::*;
33    use crate::input::{ModelInfo, OutputStyle, StatusContext, Tool, WorkspaceInfo};
34    use std::path::PathBuf;
35    use std::sync::Arc;
36
37    fn rc() -> RenderContext {
38        RenderContext::new(80)
39    }
40
41    fn ctx(output_style: Option<OutputStyle>) -> DataContext {
42        DataContext::new(StatusContext {
43            tool: Tool::ClaudeCode,
44            model: Some(ModelInfo {
45                display_name: "X".into(),
46            }),
47            workspace: Some(WorkspaceInfo {
48                project_dir: PathBuf::from("/repo"),
49                git_worktree: None,
50            }),
51            context_window: None,
52            cost: None,
53            effort: None,
54            vim: None,
55            output_style,
56            agent_name: None,
57            version: None,
58            raw: Arc::new(serde_json::Value::Null),
59        })
60    }
61
62    #[test]
63    fn renders_named_style() {
64        for name in ["default", "concise", "explanatory", "custom-flavor"] {
65            assert_eq!(
66                OutputStyleSegment
67                    .render(
68                        &ctx(Some(OutputStyle {
69                            name: name.to_string(),
70                        })),
71                        &rc(),
72                    )
73                    .unwrap(),
74                Some(RenderedSegment::new(name).with_role(Role::Muted)),
75                "for name={name}"
76            );
77        }
78    }
79
80    #[test]
81    fn hidden_when_absent() {
82        assert_eq!(OutputStyleSegment.render(&ctx(None), &rc()).unwrap(), None);
83    }
84
85    #[test]
86    fn defaults_use_expected_priority() {
87        assert_eq!(OutputStyleSegment.defaults().priority, PRIORITY);
88    }
89}