doum_cli/cli/
menu.rs

1// 메뉴 구조 및 네비게이션 시스템
2
3/// 메뉴 아이템
4#[derive(Debug, Clone)]
5pub struct MenuItem {
6    pub id: String,
7    pub label: String,
8    pub description: String,
9}
10
11impl MenuItem {
12    pub fn new(id: impl Into<String>, label: impl Into<String>, description: impl Into<String>) -> Self {
13        Self {
14            id: id.into(),
15            label: label.into(),
16            description: description.into(),
17        }
18    }
19    
20    /// 표시용 포맷 (선택 리스트에 표시)
21    pub fn display_label(&self) -> String {
22        format!("{:12} - {}", self.label, self.description)
23    }
24}
25
26/// 메뉴 컨텍스트 (네비게이션 상태 관리)
27#[derive(Debug, Clone, Copy, PartialEq)]
28pub enum MenuAction {
29    Continue,   // 현재 메뉴 계속
30    Back,       // 이전 메뉴로
31    Exit,       // 프로그램 종료
32}
33
34/// 메뉴 빌더
35pub struct MenuBuilder {
36    items: Vec<MenuItem>,
37    title: String,
38    include_back: bool,
39    include_exit: bool,
40}
41
42impl MenuBuilder {
43    pub fn new(title: impl Into<String>) -> Self {
44        Self {
45            items: Vec::new(),
46            title: title.into(),
47            include_back: false,
48            include_exit: true,
49        }
50    }
51    
52    pub fn with_back(mut self) -> Self {
53        self.include_back = true;
54        self
55    }
56    
57    pub fn with_exit(mut self, include: bool) -> Self {
58        self.include_exit = include;
59        self
60    }
61    
62    pub fn add_item(mut self, id: impl Into<String>, label: impl Into<String>, description: impl Into<String>) -> Self {
63        self.items.push(MenuItem::new(id, label, description));
64        self
65    }
66    
67    pub fn build(mut self) -> Menu {
68        let mut all_items = Vec::new();
69        
70        // Add back option
71        if self.include_back {
72            all_items.push(MenuItem::new(
73                "back",
74                "Back",
75                "Back to previous menu"
76            ));
77        }
78        
79        // Add user items
80        all_items.append(&mut self.items);
81        
82        // Add exit option
83        if self.include_exit {
84            all_items.push(MenuItem::new(
85                "exit",
86                "Exit",
87                "Exit the program"
88            ));
89        }
90        
91        Menu {
92            title: self.title,
93            items: all_items,
94        }
95    }
96}
97
98/// 메뉴
99pub struct Menu {
100    pub title: String,
101    pub items: Vec<MenuItem>,
102}
103
104impl Menu {
105    pub fn builder(title: impl Into<String>) -> MenuBuilder {
106        MenuBuilder::new(title)
107    }
108    
109    /// 메뉴 아이템 ID로 찾기
110    pub fn get_item(&self, id: &str) -> Option<&MenuItem> {
111        self.items.iter().find(|item| item.id == id)
112    }
113    
114    /// 표시용 옵션 리스트 생성
115    pub fn get_display_options(&self) -> Vec<String> {
116        self.items.iter().map(|item| item.display_label()).collect()
117    }
118    
119    /// 선택된 인덱스로부터 MenuItem 가져오기
120    pub fn get_item_by_index(&self, index: usize) -> Option<&MenuItem> {
121        self.items.get(index)
122    }
123}