1use crate::context::Context;
8
9pub type ConditionFn = dyn Fn(&Context) -> bool + Send + Sync;
11
12pub struct ActiveHelp {
14 pub message: String,
16 pub condition: Option<std::sync::Arc<ConditionFn>>,
18}
19
20impl ActiveHelp {
21 #[must_use]
31 pub fn new<S: Into<String>>(message: S) -> Self {
32 Self {
33 message: message.into(),
34 condition: None,
35 }
36 }
37
38 #[must_use]
53 pub fn with_condition<S, F>(message: S, condition: F) -> Self
54 where
55 S: Into<String>,
56 F: Fn(&Context) -> bool + Send + Sync + 'static,
57 {
58 Self {
59 message: message.into(),
60 condition: Some(std::sync::Arc::new(condition)),
61 }
62 }
63
64 #[must_use]
66 pub fn should_display(&self, ctx: &Context) -> bool {
67 self.condition
68 .as_ref()
69 .map_or(true, |condition| condition(ctx))
70 }
71}
72
73impl Clone for ActiveHelp {
74 fn clone(&self) -> Self {
75 Self {
76 message: self.message.clone(),
77 condition: self.condition.clone(),
78 }
79 }
80}
81
82impl std::fmt::Debug for ActiveHelp {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 f.debug_struct("ActiveHelp")
85 .field("message", &self.message)
86 .field("condition", &self.condition.is_some())
87 .finish()
88 }
89}
90
91#[derive(Clone, Debug)]
93pub struct ActiveHelpConfig {
94 pub show_on_double_tab: bool,
96 pub show_on_no_completions: bool,
98 pub disabled: bool,
100 pub disable_env_var: Option<String>,
102}
103
104impl Default for ActiveHelpConfig {
105 fn default() -> Self {
106 Self {
107 show_on_double_tab: true,
108 show_on_no_completions: true,
109 disabled: false,
110 disable_env_var: Some("COBRA_ACTIVE_HELP".to_string()), }
112 }
113}
114
115impl ActiveHelpConfig {
116 #[must_use]
118 pub fn is_enabled(&self) -> bool {
119 if self.disabled {
120 return false;
121 }
122
123 if let Some(ref env_var) = self.disable_env_var {
125 if let Ok(value) = std::env::var(env_var) {
126 return !matches!(value.to_lowercase().as_str(), "0" | "false");
128 }
129 }
130
131 true
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138
139 #[test]
140 fn test_active_help_new() {
141 let help = ActiveHelp::new("Test message");
142 assert_eq!(help.message, "Test message");
143 assert!(help.condition.is_none());
144 }
145
146 #[test]
147 fn test_active_help_with_condition() {
148 let help = ActiveHelp::with_condition("Conditional help", |_ctx| true);
149 assert_eq!(help.message, "Conditional help");
150 assert!(help.condition.is_some());
151 }
152
153 #[test]
154 fn test_should_display() {
155 let ctx = Context::new(vec![]);
156
157 let help = ActiveHelp::new("Always shown");
159 assert!(help.should_display(&ctx));
160
161 let help = ActiveHelp::with_condition("Also shown", |_| true);
163 assert!(help.should_display(&ctx));
164
165 let help = ActiveHelp::with_condition("Never shown", |_| false);
167 assert!(!help.should_display(&ctx));
168 }
169
170 #[test]
171 fn test_active_help_config_default() {
172 let config = ActiveHelpConfig::default();
173 assert!(config.show_on_double_tab);
174 assert!(config.show_on_no_completions);
175 assert!(!config.disabled);
176 assert_eq!(
177 config.disable_env_var,
178 Some("COBRA_ACTIVE_HELP".to_string())
179 );
180 }
181
182 #[test]
183 fn test_active_help_config_is_enabled() {
184 let config = ActiveHelpConfig::default();
186 assert!(config.is_enabled());
187
188 let config = ActiveHelpConfig {
190 disabled: true,
191 ..Default::default()
192 };
193 assert!(!config.is_enabled());
194 }
195}