1use anstyle::{AnsiColor, Style};
6
7use crate::providers::ReviewState;
8
9pub const BRANCH: Style = AnsiColor::Cyan.on_default();
11pub const CURRENT: Style = AnsiColor::Green.on_default().bold();
13pub const DIM: Style = Style::new().dimmed();
15pub const HINT: Style = AnsiColor::Cyan.on_default();
17pub const WARN: Style = AnsiColor::Yellow.on_default();
19
20pub const OPEN: Style = AnsiColor::Green.on_default();
23pub const MERGED: Style = AnsiColor::Magenta.on_default();
24pub const CLOSED: Style = AnsiColor::Red.on_default();
25
26pub fn paint(style: Style, text: &str) -> String {
27 format!("{style}{text}{style:#}")
28}
29
30pub fn state(state: &ReviewState) -> String {
32 let style = match state {
33 ReviewState::Open => OPEN,
34 ReviewState::Merged => MERGED,
35 ReviewState::Closed => CLOSED,
36 ReviewState::Unknown(_) => DIM,
37 };
38 paint(style, &state.to_string())
39}
40
41#[cfg(test)]
42mod tests {
43 use super::*;
44
45 #[test]
46 fn paint_wraps_text_in_escape_codes() {
47 let painted = paint(BRANCH, "feature/a");
48 assert!(painted.contains("feature/a"));
49 assert!(painted.starts_with('\u{1b}'));
50 assert!(painted.ends_with('m'));
51 }
52
53 #[test]
54 fn state_uses_the_ledger_palette() {
55 assert!(state(&ReviewState::Open).contains("open"));
56 assert!(state(&ReviewState::Merged).contains("merged"));
57 assert!(state(&ReviewState::Closed).contains("closed"));
58 assert_ne!(
59 state(&ReviewState::Open),
60 state(&ReviewState::Merged),
61 "states should not share a style"
62 );
63 }
64}