stynx_code_services/tips/
mod.rs1use std::collections::HashSet;
2use std::sync::Mutex;
3
4pub trait TipProvider: Send + Sync {
5 fn get_tip(&self) -> Option<String>;
6 fn mark_shown(&self, tip_id: &str);
7}
8
9struct Tip {
10 id: &'static str,
11 text: &'static str,
12}
13
14const TIPS: &[Tip] = &[
15 Tip { id: "shortcut_ctrl_c", text: "Press Ctrl+C to interrupt a running tool." },
16 Tip { id: "slash_help", text: "Type /help to see all available slash commands." },
17 Tip { id: "slash_compact", text: "Use /compact to summarize the conversation and free up context." },
18 Tip { id: "multi_turn", text: "The assistant remembers context across turns in the same session." },
19 Tip { id: "tool_permission", text: "You can allow tools permanently with 'Always allow' to skip confirmation prompts." },
20 Tip { id: "shift_tab", text: "Press Shift+Tab to toggle between single-line and multi-line input mode." },
21 Tip { id: "slash_config", text: "Use /config to view or change settings during a session." },
22 Tip { id: "memory", text: "The assistant can remember things across sessions when you ask it to." },
23];
24
25pub struct StaticTipProvider {
26 shown: Mutex<HashSet<String>>,
27}
28
29impl StaticTipProvider {
30 pub fn new() -> Self {
31 Self {
32 shown: Mutex::new(HashSet::new()),
33 }
34 }
35}
36
37impl TipProvider for StaticTipProvider {
38 fn get_tip(&self) -> Option<String> {
39 let shown = self.shown.lock().unwrap_or_else(|e| e.into_inner());
40 for tip in TIPS {
41 if !shown.contains(tip.id) {
42 return Some(tip.text.to_string());
43 }
44 }
45 None
46 }
47
48 fn mark_shown(&self, tip_id: &str) {
49 let mut shown = self.shown.lock().unwrap_or_else(|e| e.into_inner());
50 shown.insert(tip_id.to_string());
51 }
52}