glues_tui/context/
entry.rs

1use {
2    crate::{
3        action::{Action, OpenProxyStep, TuiAction},
4        config::{self, LAST_PROXY_URL},
5        input::KeyCode,
6        logger::*,
7        theme::THEME,
8    },
9    glues_core::EntryEvent,
10    ratatui::{style::Stylize, text::Line, widgets::ListState},
11};
12
13#[cfg(target_arch = "wasm32")]
14use crate::config::LAST_IDB_NAMESPACE;
15
16#[cfg(not(target_arch = "wasm32"))]
17use crate::{
18    action::{OpenGitStep, OpenMongoStep},
19    config::{LAST_FILE_PATH, LAST_GIT_PATH, LAST_MONGO_CONN_STR, LAST_REDB_PATH},
20};
21
22pub const INSTANT: &str = "[i] Instant";
23#[cfg(target_arch = "wasm32")]
24pub const INDEXED_DB: &str = "[d] IndexedDB";
25#[cfg(not(target_arch = "wasm32"))]
26pub const FILE: &str = "[l] Local";
27#[cfg(not(target_arch = "wasm32"))]
28pub const REDB: &str = "[r] redb";
29#[cfg(not(target_arch = "wasm32"))]
30pub const GIT: &str = "[g] Git";
31#[cfg(not(target_arch = "wasm32"))]
32pub const MONGO: &str = "[m] MongoDB";
33#[cfg(target_arch = "wasm32")]
34pub const PROXY: &str = "[p] Proxy";
35#[cfg(not(target_arch = "wasm32"))]
36pub const PROXY: &str = "[p] Proxy";
37pub const HELP: &str = "[h] Help";
38pub const THEME_MENU: &str = "[t] Theme";
39pub const QUIT: &str = "[q] Quit";
40
41#[cfg(not(target_arch = "wasm32"))]
42pub const MENU_ITEMS: [&str; 9] = [
43    INSTANT, FILE, REDB, GIT, MONGO, PROXY, HELP, THEME_MENU, QUIT,
44];
45#[cfg(target_arch = "wasm32")]
46pub const MENU_ITEMS: [&str; 5] = [INSTANT, INDEXED_DB, PROXY, HELP, THEME_MENU];
47
48pub struct EntryContext {
49    pub list_state: ListState,
50}
51
52impl Default for EntryContext {
53    fn default() -> Self {
54        Self {
55            list_state: ListState::default().with_selected(Some(0)),
56        }
57    }
58}
59
60impl EntryContext {
61    pub async fn consume(&mut self, code: KeyCode) -> Action {
62        #[cfg(not(target_arch = "wasm32"))]
63        let open = |key, action: TuiAction| async move {
64            TuiAction::Prompt {
65                message: vec![
66                    Line::raw("Enter the path:"),
67                    Line::from("If the path does not exist, it will be created.".fg(THEME.hint)),
68                ],
69                action: Box::new(action.into()),
70                default: config::get(key).await,
71            }
72            .into()
73        };
74
75        #[cfg(not(target_arch = "wasm32"))]
76        let open_redb = || async move {
77            TuiAction::Prompt {
78                message: vec![
79                    Line::raw("Provide the redb database path:"),
80                    Line::from(
81                        "Glues will create or reuse the single-file redb database.".fg(THEME.hint),
82                    ),
83                ],
84                action: Box::new(TuiAction::OpenRedb.into()),
85                default: config::get(LAST_REDB_PATH).await,
86            }
87            .into()
88        };
89
90        #[cfg(target_arch = "wasm32")]
91        let open_indexed_db = || async move {
92            TuiAction::Prompt {
93                message: vec![
94                    Line::raw("Enter the IndexedDB namespace:"),
95                    Line::from("Leave empty to use the default namespace (glues).".fg(THEME.hint)),
96                ],
97                action: Box::new(TuiAction::OpenIndexedDb.into()),
98                default: config::get(LAST_IDB_NAMESPACE).await,
99            }
100            .into()
101        };
102
103        #[cfg(not(target_arch = "wasm32"))]
104        let open_git = || async move {
105            TuiAction::Prompt {
106                message: vec![
107                    Line::raw("Enter the git repository path:"),
108                    Line::from("The path must contain an existing .git repository.".fg(THEME.hint)),
109                    Line::from("otherwise, an error will occur.".fg(THEME.hint)),
110                ],
111                action: Box::new(TuiAction::OpenGit(OpenGitStep::Path).into()),
112                default: config::get(LAST_GIT_PATH).await,
113            }
114            .into()
115        };
116
117        #[cfg(not(target_arch = "wasm32"))]
118        let open_mongo = || async move {
119            TuiAction::Prompt {
120                message: vec![
121                    Line::raw("Enter the MongoDB connection string:"),
122                    Line::from("e.g. mongodb://localhost:27017".fg(THEME.hint)),
123                ],
124                action: Box::new(TuiAction::OpenMongo(OpenMongoStep::ConnStr).into()),
125                default: config::get(LAST_MONGO_CONN_STR).await,
126            }
127            .into()
128        };
129
130        let open_proxy = || async move {
131            TuiAction::Prompt {
132                message: vec![
133                    Line::raw("Enter the proxy server URL:"),
134                    Line::from("e.g. http://127.0.0.1:4000".fg(THEME.hint)),
135                ],
136                action: Box::new(TuiAction::OpenProxy(OpenProxyStep::Url).into()),
137                default: config::get(LAST_PROXY_URL).await,
138            }
139            .into()
140        };
141
142        match code {
143            #[cfg(not(target_arch = "wasm32"))]
144            KeyCode::Char('q') => TuiAction::Quit.into(),
145            KeyCode::Char('j') | KeyCode::Down => {
146                self.list_state.select_next();
147                Action::None
148            }
149            KeyCode::Char('k') | KeyCode::Up => {
150                self.list_state.select_previous();
151                Action::None
152            }
153            KeyCode::Char('i') => EntryEvent::OpenMemory.into(),
154            #[cfg(target_arch = "wasm32")]
155            KeyCode::Char('d') => open_indexed_db().await,
156            #[cfg(not(target_arch = "wasm32"))]
157            KeyCode::Char('l') => open(LAST_FILE_PATH, TuiAction::OpenFile).await,
158            #[cfg(not(target_arch = "wasm32"))]
159            KeyCode::Char('r') => open_redb().await,
160            #[cfg(not(target_arch = "wasm32"))]
161            KeyCode::Char('g') => open_git().await,
162            #[cfg(not(target_arch = "wasm32"))]
163            KeyCode::Char('m') => open_mongo().await,
164            KeyCode::Char('p') => open_proxy().await,
165            KeyCode::Char('h') => TuiAction::Help.into(),
166            KeyCode::Char('t') => TuiAction::OpenThemeMenu.into(),
167
168            KeyCode::Enter => {
169                let i = self
170                    .list_state
171                    .selected()
172                    .log_expect("EntryContext::consume: selected is None. This should not happen.");
173                match MENU_ITEMS[i] {
174                    INSTANT => EntryEvent::OpenMemory.into(),
175                    #[cfg(target_arch = "wasm32")]
176                    INDEXED_DB => open_indexed_db().await,
177                    #[cfg(not(target_arch = "wasm32"))]
178                    FILE => open(LAST_FILE_PATH, TuiAction::OpenFile).await,
179                    #[cfg(not(target_arch = "wasm32"))]
180                    REDB => open_redb().await,
181                    #[cfg(not(target_arch = "wasm32"))]
182                    GIT => open_git().await,
183                    #[cfg(not(target_arch = "wasm32"))]
184                    MONGO => open_mongo().await,
185                    PROXY => open_proxy().await,
186                    HELP => TuiAction::Help.into(),
187                    THEME_MENU => TuiAction::OpenThemeMenu.into(),
188                    #[cfg(not(target_arch = "wasm32"))]
189                    QUIT => TuiAction::Quit.into(),
190                    _ => Action::None,
191                }
192            }
193            _ => Action::PassThrough,
194        }
195    }
196}