Skip to main content

xei_core/
call_hierarchy.rs

1//! Call hierarchy panel state (LSP-backed).
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub enum CallDirection {
5    Incoming,
6    Outgoing,
7}
8
9impl CallDirection {
10    pub fn label(self) -> &'static str {
11        match self {
12            CallDirection::Incoming => "incoming",
13            CallDirection::Outgoing => "outgoing",
14        }
15    }
16
17    pub fn toggle(self) -> Self {
18        match self {
19            CallDirection::Incoming => CallDirection::Outgoing,
20            CallDirection::Outgoing => CallDirection::Incoming,
21        }
22    }
23}
24
25#[derive(Debug, Clone)]
26pub struct CallItem {
27    pub name: String,
28    pub detail: String,
29    pub kind: String,
30    pub path: String,
31    pub row: usize,
32    pub col: usize,
33    /// Full CallHierarchyItem JSON for follow-up requests.
34    pub raw_json: String,
35}
36
37#[derive(Debug, Clone)]
38pub struct CallHierarchyState {
39    pub open: bool,
40    pub direction: CallDirection,
41    pub root_name: String,
42    pub items: Vec<CallItem>,
43    pub selected: usize,
44    pub loading: bool,
45    pub message: String,
46}
47
48impl Default for CallHierarchyState {
49    fn default() -> Self {
50        Self {
51            open: false,
52            direction: CallDirection::Incoming,
53            root_name: String::new(),
54            items: Vec::new(),
55            selected: 0,
56            loading: false,
57            message: String::new(),
58        }
59    }
60}
61
62impl CallHierarchyState {
63    pub fn new() -> Self {
64        Self::default()
65    }
66
67    pub fn close(&mut self) {
68        self.open = false;
69        self.items.clear();
70        self.loading = false;
71        self.message.clear();
72    }
73
74    pub fn begin(&mut self, root_name: &str, direction: CallDirection) {
75        self.open = true;
76        self.direction = direction;
77        self.root_name = root_name.to_string();
78        self.items.clear();
79        self.selected = 0;
80        self.loading = true;
81        self.message = format!("Call hierarchy ({})…", direction.label());
82    }
83
84    pub fn set_items(&mut self, items: Vec<CallItem>) {
85        self.items = items;
86        self.selected = 0;
87        self.loading = false;
88        self.message = if self.items.is_empty() {
89            format!("No {} calls", self.direction.label())
90        } else {
91            format!(
92                "{} · {} {} call(s)",
93                self.root_name,
94                self.items.len(),
95                self.direction.label()
96            )
97        };
98    }
99
100    pub fn move_sel(&mut self, delta: isize) {
101        if self.items.is_empty() {
102            return;
103        }
104        let n = self.items.len() as isize;
105        let cur = self.selected as isize + delta;
106        self.selected = cur.rem_euclid(n) as usize;
107    }
108
109    pub fn selected_item(&self) -> Option<&CallItem> {
110        self.items.get(self.selected)
111    }
112}