purple_ssh/app/
snippet_state.rs1use crate::app::SnippetFormBaseline;
2use crate::app::forms::{SnippetForm, SnippetOutputState, SnippetParamFormState};
3use crate::snippet::{Snippet, SnippetStore};
4
5pub struct SnippetState {
10 pub(in crate::app) store: SnippetStore,
11 pub(crate) form: SnippetForm,
15 pub(in crate::app) pending: Option<(Snippet, Vec<String>)>,
16 pub(crate) output: Option<SnippetOutputState>,
20 pub(crate) param_form: Option<SnippetParamFormState>,
21 pub(in crate::app) pending_terminal: bool,
22 pub(in crate::app) form_baseline: Option<SnippetFormBaseline>,
23 pub(crate) pending_delete: Option<usize>,
26}
27
28impl Default for SnippetState {
29 fn default() -> Self {
30 Self {
31 store: SnippetStore::default(),
32 form: SnippetForm::new(),
33 pending: None,
34 output: None,
35 param_form: None,
36 pending_terminal: false,
37 form_baseline: None,
38 pending_delete: None,
39 }
40 }
41}
42
43impl SnippetState {
44 pub fn store(&self) -> &SnippetStore {
45 &self.store
46 }
47
48 pub fn store_mut(&mut self) -> &mut SnippetStore {
49 &mut self.store
50 }
51
52 pub fn pending(&self) -> Option<&(Snippet, Vec<String>)> {
53 self.pending.as_ref()
54 }
55
56 pub fn take_pending(&mut self) -> Option<(Snippet, Vec<String>)> {
57 self.pending.take()
58 }
59
60 pub fn set_pending(&mut self, value: Option<(Snippet, Vec<String>)>) {
61 self.pending = value;
62 }
63
64 pub fn pending_terminal(&self) -> bool {
65 self.pending_terminal
66 }
67
68 pub fn set_pending_terminal(&mut self, value: bool) {
69 self.pending_terminal = value;
70 }
71
72 pub fn form_baseline(&self) -> Option<&SnippetFormBaseline> {
73 self.form_baseline.as_ref()
74 }
75
76 pub fn set_form_baseline(&mut self, baseline: Option<SnippetFormBaseline>) {
77 self.form_baseline = baseline;
78 }
79
80 pub fn with_store_loaded() -> Self {
82 Self {
83 store: crate::snippet::SnippetStore::load(),
84 ..Self::default()
85 }
86 }
87
88 pub fn request_delete(&mut self, idx: usize) {
91 self.pending_delete = Some(idx);
92 }
93
94 pub fn cancel_delete(&mut self) {
96 self.pending_delete = None;
97 }
98
99 pub fn close_param_form(&mut self) {
104 self.param_form = None;
105 self.pending_terminal = false;
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn default_is_empty() {
115 let s = SnippetState::default();
116 assert!(s.pending.is_none());
117 assert!(s.output.is_none());
118 assert!(s.param_form.is_none());
119 assert!(!s.pending_terminal);
120 assert!(s.form_baseline.is_none());
121 assert!(s.pending_delete.is_none());
122 }
123
124 #[test]
125 fn request_delete_sets_pending_delete_to_some_idx() {
126 let mut s = SnippetState::default();
127 s.request_delete(3);
128 assert_eq!(s.pending_delete, Some(3));
129 }
130
131 #[test]
132 fn cancel_delete_clears_pending_delete() {
133 let mut s = SnippetState {
134 pending_delete: Some(2),
135 ..Default::default()
136 };
137 s.cancel_delete();
138 assert!(s.pending_delete.is_none());
139 }
140
141 #[test]
142 fn request_delete_overwrites_existing_pending() {
143 let mut s = SnippetState {
144 pending_delete: Some(1),
145 ..Default::default()
146 };
147 s.request_delete(7);
148 assert_eq!(s.pending_delete, Some(7));
149 }
150
151 #[test]
152 fn close_param_form_clears_param_form_and_pending_terminal() {
153 let mut s = SnippetState {
154 param_form: Some(SnippetParamFormState::new(&[])),
155 pending_terminal: true,
156 ..Default::default()
157 };
158 s.close_param_form();
159 assert!(s.param_form.is_none());
160 assert!(!s.pending_terminal);
161 }
162
163 #[test]
164 fn close_param_form_preserves_pending_output_and_store() {
165 use crate::snippet::Snippet;
166 let mut s = SnippetState {
167 param_form: Some(SnippetParamFormState::new(&[])),
168 pending_terminal: true,
169 pending: Some((
170 Snippet {
171 name: "ls".into(),
172 command: "ls -la".into(),
173 description: String::new(),
174 },
175 vec!["host-a".into()],
176 )),
177 ..Default::default()
178 };
179
180 s.close_param_form();
181
182 assert!(
183 s.pending.is_some(),
184 "pending stays for the consumer to read"
185 );
186 assert!(s.pending_delete.is_none());
187 }
188
189 #[test]
190 fn close_param_form_is_idempotent_when_already_none() {
191 let mut s = SnippetState::default();
192 s.close_param_form();
193 s.close_param_form();
194 assert!(s.param_form.is_none());
195 assert!(!s.pending_terminal);
196 }
197}