Skip to main content

stynx_code_services/tips/
mod.rs

1use 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}