Skip to main content

linesmith_core/segments/
effort.rs

1//! Effort segment: renders the current `/effort` level. Hidden when the
2//! payload doesn't carry it.
3//!
4//! Claude Code does not currently re-emit the effort level when the user
5//! runs `/effort max` or similar
6//! ([ccstatusline#239](https://github.com/sirmalloc/ccstatusline/issues/239)).
7//! Until that ships upstream, this segment will be hidden in practice.
8//! Segment is shipped now so it lights up automatically when the payload
9//! arrives.
10
11use super::{RenderContext, RenderResult, RenderedSegment, Segment, SegmentDefaults};
12use crate::data_context::DataContext;
13use crate::theme::Role;
14
15pub struct EffortSegment;
16
17/// Informational; drops before cost (192), kept past rate-limit (96).
18const PRIORITY: u8 = 160;
19
20impl Segment for EffortSegment {
21    fn render(&self, ctx: &DataContext, _rc: &RenderContext) -> RenderResult {
22        let Some(effort) = ctx.status.effort else {
23            crate::lsm_debug!("effort: status.effort absent; hiding");
24            return Ok(None);
25        };
26        Ok(Some(
27            RenderedSegment::new(effort.as_str()).with_role(Role::Muted),
28        ))
29    }
30
31    fn defaults(&self) -> SegmentDefaults {
32        SegmentDefaults::with_priority(PRIORITY)
33    }
34}
35
36#[cfg(test)]
37mod tests {
38    use super::*;
39    use crate::input::{EffortLevel, ModelInfo, StatusContext, Tool, WorkspaceInfo};
40    use std::path::PathBuf;
41    use std::sync::Arc;
42
43    fn rc() -> RenderContext {
44        RenderContext::new(80)
45    }
46
47    fn ctx(effort: Option<EffortLevel>) -> DataContext {
48        DataContext::new(StatusContext {
49            tool: Tool::ClaudeCode,
50            model: Some(ModelInfo {
51                display_name: "X".into(),
52            }),
53            workspace: Some(WorkspaceInfo {
54                project_dir: PathBuf::from("/repo"),
55                git_worktree: None,
56            }),
57            context_window: None,
58            cost: None,
59            effort,
60            vim: None,
61            output_style: None,
62            agent_name: None,
63            version: None,
64            raw: Arc::new(serde_json::Value::Null),
65        })
66    }
67
68    #[test]
69    fn renders_each_level() {
70        for (level, expected) in [
71            (EffortLevel::Low, "low"),
72            (EffortLevel::Medium, "medium"),
73            (EffortLevel::High, "high"),
74            (EffortLevel::Max, "max"),
75            (EffortLevel::XHigh, "xhigh"),
76        ] {
77            assert_eq!(
78                EffortSegment.render(&ctx(Some(level)), &rc()).unwrap(),
79                Some(RenderedSegment::new(expected).with_role(Role::Muted))
80            );
81        }
82    }
83
84    #[test]
85    fn hidden_when_effort_absent() {
86        assert_eq!(EffortSegment.render(&ctx(None), &rc()).unwrap(), None);
87    }
88
89    #[test]
90    fn defaults_use_expected_priority() {
91        assert_eq!(EffortSegment.defaults().priority, PRIORITY);
92    }
93}