1mod convert;
17mod edit;
18mod eval;
19mod form_options;
20mod mutation;
21
22use std::collections::HashMap;
23
24use crate::overlay::OverlayStack;
25use crate::route::Route;
26use crate::tabs::config::ConfigTab;
27use crate::tabs::list::ListTab;
28use crate::tabs::nms::ConsoleState;
29use crate::tabs::nms_eval::ConsoleEval;
30use crate::tabs::reports::ReportsTab;
31use crate::view::{Tab, ViewId, ViewMut, ViewRef};
32use crate::widgets::{EditMode, Editor};
33use cli_core::render::schema;
34use plotting::ChartSpec;
35use sqlx::types::Uuid;
36
37pub struct CmdLine {
39 pub editor: Editor,
40 pub active: bool,
41 pub completions: Vec<String>,
43}
44
45impl CmdLine {
46 fn new(edit_mode: EditMode) -> Self {
47 Self {
48 editor: Editor::new(edit_mode),
49 active: false,
50 completions: Vec::new(),
51 }
52 }
53}
54
55pub struct App {
56 pub user_id: Uuid,
57 pub active_tab: Tab,
58 pub overlays: OverlayStack,
59 pub cmdline: CmdLine,
60 pub edit_mode: EditMode,
61 pub status: String,
62 pub should_quit: bool,
63 pub console_focused: bool,
65 console_eval: Option<ConsoleEval>,
67 pending_chart: Option<ChartSpec>,
69 pending_routes: HashMap<i64, Route>,
71 form_options_seq: u64,
74 pub accounts: ListTab,
75 pub transactions: ListTab,
76 pub commodities: ListTab,
77 pub reports: ReportsTab,
78 pub config: ConfigTab,
79 pub console: ConsoleState,
80}
81
82impl App {
83 #[must_use]
84 pub fn new(user_id: Uuid, edit_mode: EditMode) -> Self {
85 Self {
86 user_id,
87 active_tab: Tab::Reports,
88 overlays: OverlayStack::new(),
89 cmdline: CmdLine::new(edit_mode),
90 edit_mode,
91 status: String::new(),
92 should_quit: false,
93 console_focused: false,
94 console_eval: None,
95 pending_chart: None,
96 pending_routes: HashMap::new(),
97 form_options_seq: 0,
98 accounts: ListTab::new("(list-accounts)", &schema::ACCOUNTS),
99 transactions: ListTab::new("(list-transactions \"\")", &schema::TRANSACTIONS),
100 commodities: ListTab::new("(list-commodities)", &schema::COMMODITIES),
101 reports: ReportsTab::new(),
102 config: ConfigTab::new(),
103 console: ConsoleState::new(),
104 }
105 }
106
107 pub fn active_view(&self) -> ViewRef<'_> {
108 match self.active_tab {
109 ViewId::Accounts => ViewRef::List(ViewId::Accounts, &self.accounts),
110 ViewId::Transactions => ViewRef::List(ViewId::Transactions, &self.transactions),
111 ViewId::Commodities => ViewRef::List(ViewId::Commodities, &self.commodities),
112 ViewId::Reports => ViewRef::Reports(&self.reports),
113 ViewId::Config => ViewRef::Config(&self.config),
114 ViewId::Console => ViewRef::Console(&self.console),
115 }
116 }
117
118 pub fn active_view_mut(&mut self) -> ViewMut<'_> {
119 match self.active_tab {
120 ViewId::Accounts => ViewMut::List(ViewId::Accounts, &mut self.accounts),
121 ViewId::Transactions => ViewMut::List(ViewId::Transactions, &mut self.transactions),
122 ViewId::Commodities => ViewMut::List(ViewId::Commodities, &mut self.commodities),
123 ViewId::Reports => ViewMut::Reports(&mut self.reports),
124 ViewId::Config => ViewMut::Config(&mut self.config),
125 ViewId::Console => ViewMut::Console(&mut self.console),
126 }
127 }
128
129 pub fn queue_chart(&mut self, spec: ChartSpec) {
130 self.pending_chart = Some(spec);
131 }
132
133 pub fn take_pending_chart(&mut self) -> Option<ChartSpec> {
134 self.pending_chart.take()
135 }
136
137 fn activate_tab(&mut self, tab: Tab) {
138 if tab != Tab::Console {
139 self.console_focused = false;
140 }
141 self.active_tab = tab;
142 self.ensure_tab_loaded(tab);
143 }
144
145 pub fn next_tab(&mut self) {
146 let idx = self.active_tab.index();
147 self.activate_tab(Tab::ALL[(idx + 1) % Tab::ALL.len()]);
148 }
149
150 pub fn previous_tab(&mut self) {
151 let idx = self.active_tab.index();
152 let len = Tab::ALL.len();
153 self.activate_tab(Tab::ALL[(idx + len - 1) % len]);
154 }
155
156 pub fn switch_tab(&mut self, tab: Tab) {
157 self.activate_tab(tab);
158 }
159
160 pub fn open_command_line(&mut self) {
161 self.cmdline.editor = Editor::new(self.edit_mode);
162 self.cmdline.active = true;
163 self.cmdline.completions.clear();
164 }
165
166 pub fn close_command_line(&mut self) {
167 self.cmdline.active = false;
168 self.cmdline.completions.clear();
169 }
170
171 pub fn set_status(&mut self, msg: impl Into<String>) {
172 self.status = msg.into();
173 }
174
175 pub fn request_quit(&mut self) {
176 self.should_quit = true;
177 }
178
179 pub fn set_edit_mode(&mut self, mode: EditMode) {
180 self.edit_mode = mode;
181 self.cmdline.editor.set_mode(mode);
182 }
183
184 pub fn attach_console(&mut self, eval: ConsoleEval) {
185 self.console_eval = Some(eval);
186 }
187}
188
189#[cfg(test)]
190mod tests;