Skip to main content

linesmith_core/segments/
vim.rs

1//! Vim segment: renders Claude Code's active vim mode (normal, insert,
2//! visual, command, replace). Hidden when the payload doesn't carry
3//! `vim`. 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 VimSegment;
10
11/// Informational; drops before cost (192), kept past rate-limit (96).
12const PRIORITY: u8 = 160;
13
14impl Segment for VimSegment {
15    fn render(&self, ctx: &DataContext, _rc: &RenderContext) -> RenderResult {
16        let Some(mode) = ctx.status.vim else {
17            crate::lsm_debug!("vim: status.vim absent; hiding");
18            return Ok(None);
19        };
20        Ok(Some(
21            RenderedSegment::new(mode.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, StatusContext, Tool, VimMode, 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(vim: Option<VimMode>) -> 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,
55            output_style: None,
56            agent_name: None,
57            version: None,
58            raw: Arc::new(serde_json::Value::Null),
59        })
60    }
61
62    #[test]
63    fn renders_each_mode() {
64        for (mode, expected) in [
65            (VimMode::Normal, "normal"),
66            (VimMode::Insert, "insert"),
67            (VimMode::Visual, "visual"),
68            (VimMode::Command, "command"),
69            (VimMode::Replace, "replace"),
70        ] {
71            assert_eq!(
72                VimSegment.render(&ctx(Some(mode)), &rc()).unwrap(),
73                Some(RenderedSegment::new(expected).with_role(Role::Muted))
74            );
75        }
76    }
77
78    #[test]
79    fn hidden_when_absent() {
80        assert_eq!(VimSegment.render(&ctx(None), &rc()).unwrap(), None);
81    }
82
83    #[test]
84    fn defaults_use_expected_priority() {
85        assert_eq!(VimSegment.defaults().priority, PRIORITY);
86    }
87}