vtcode_commons/
modal_hints.rs1pub const APPROVAL_NAVIGATE_DENY: &str = "Use ↑↓ or Tab to navigate • Enter to select • Esc to deny";
10pub const APPROVAL_NAVIGATE_CANCEL: &str = "Use ↑↓ or Tab to navigate • Enter to select • Esc to cancel";
12pub const APPROVAL_NAVIGATE_STOP: &str = "Use ↑↓ or Tab to navigate • Enter to select • Esc to stop";
14
15pub fn choose_handling_line(object: &str) -> String {
17 format!("Choose how to handle {object}:")
18}
19
20pub fn truncate_modal_text(text: &str, max_chars: usize) -> String {
23 if text.chars().count() <= max_chars {
24 return text.to_string();
25 }
26 let mut truncated = text.chars().take(max_chars.saturating_sub(1)).collect::<String>();
27 truncated.push('…');
28 truncated
29}
30
31#[cfg(test)]
32mod tests {
33 use super::*;
34
35 #[test]
36 fn approval_hints_share_navigation_prefix_but_differ_by_exit_verb() {
37 for hint in [APPROVAL_NAVIGATE_DENY, APPROVAL_NAVIGATE_CANCEL, APPROVAL_NAVIGATE_STOP] {
38 assert!(hint.starts_with("Use ↑↓ or Tab to navigate • Enter to select • Esc to "));
39 }
40 assert!(APPROVAL_NAVIGATE_DENY.ends_with("deny"));
41 assert!(APPROVAL_NAVIGATE_CANCEL.ends_with("cancel"));
42 assert!(APPROVAL_NAVIGATE_STOP.ends_with("stop"));
43 }
44
45 #[test]
46 fn choose_handling_line_interpolates_object_as_sentence() {
47 assert_eq!(choose_handling_line("this tool"), "Choose how to handle this tool:");
48 assert_eq!(
49 choose_handling_line("workspace lifecycle hooks"),
50 "Choose how to handle workspace lifecycle hooks:"
51 );
52 }
53
54 #[test]
55 fn truncate_modal_text_marks_truncation_with_ellipsis_only_when_shortened() {
56 assert_eq!(truncate_modal_text("short", 10), "short");
57 assert_eq!(truncate_modal_text("exactly-ten", 11), "exactly-ten");
58 assert_eq!(truncate_modal_text("over the limit text", 10), "over the …");
59 }
60}