@@ -17,16 +17,16 @@ use crate::os::Os;
1717
1818#[ derive( Debug , PartialEq , Subcommand ) ]
1919pub enum TodoSubcommand {
20- // Show all tracked to-do lists
20+ /// Show all tracked to-do lists
2121 Show ,
2222
23- // Clear completed to-do lists
23+ /// Delete all completed to-do lists
2424 ClearFinished ,
25-
26- // Resume a selected to-do list
25+
26+ /// Resume a selected to-do list
2727 Resume ,
28-
29- // View a to-do list
28+
29+ /// View a to-do list
3030 View ,
3131}
3232
@@ -61,7 +61,7 @@ impl TodoSubcommand {
6161 Self :: Show => match Self :: get_descriptions_and_statuses ( os) {
6262 Ok ( entries) => {
6363 if entries. is_empty ( ) {
64- execute ! ( session. stderr, style:: Print ( "No to-do lists to show" ) , ) ?;
64+ execute ! ( session. stderr, style:: Print ( "No to-do lists to show\n " ) , ) ?;
6565 }
6666 for e in entries {
6767 execute ! ( session. stderr, style:: Print ( e) , style:: Print ( "\n " ) , ) ?;
@@ -70,16 +70,46 @@ impl TodoSubcommand {
7070 Err ( _) => return Err ( ChatError :: Custom ( "Could not show to-do lists" . into ( ) ) ) ,
7171 } ,
7272 Self :: ClearFinished => {
73-
73+ let entries = match os. database . get_all_todos ( ) {
74+ Ok ( e) => e,
75+ Err ( _) => return Err ( ChatError :: Custom ( "Could not get all to-do lists" . into ( ) ) ) ,
76+ } ;
77+ let mut cleared_one = false ;
78+ for ( id, value) in entries. iter ( ) {
79+ let temp_struct = match value. as_str ( ) {
80+ Some ( s) => match serde_json:: from_str :: < TodoState > ( s) {
81+ Ok ( state) => state,
82+ Err ( _) => continue ,
83+ } ,
84+ None => continue ,
85+ } ;
86+ if temp_struct. completed . iter ( ) . all ( |b| * b) {
87+ match os. database . delete_todo ( id) {
88+ Ok ( _) => cleared_one = true ,
89+ Err ( _) => return Err ( ChatError :: Custom ( "Could not delete to-do list" . into ( ) ) ) ,
90+ } ;
91+ }
92+ }
93+ if cleared_one {
94+ execute ! (
95+ session. stderr,
96+ style:: Print ( "✔ Cleared finished to-do lists!\n " . green( ) )
97+ ) ?;
98+ } else {
99+ execute ! (
100+ session. stderr,
101+ style:: Print ( "No finished to-do lists to clear!\n " . green( ) )
102+ ) ?;
103+ }
74104 } ,
75105 Self :: Resume => {
76106 match Self :: get_descriptions_and_statuses ( os) {
77107 Ok ( entries) => {
78108 if entries. is_empty ( ) {
79- execute ! ( session. stderr, style:: Print ( "No to-do lists to show" ) , ) ?;
109+ execute ! ( session. stderr, style:: Print ( "No to-do lists to show\n " ) , ) ?;
80110 } else {
81111 let selection = FuzzySelect :: new ( )
82- . with_prompt ( "Select task to resume:" )
112+ . with_prompt ( "Select a to-do list to resume:" )
83113 . items ( & entries)
84114 . report ( false )
85115 . interact_opt ( )
@@ -100,41 +130,47 @@ impl TodoSubcommand {
100130 Err ( _) => return Err ( ChatError :: Custom ( "Could not show to-do lists" . into ( ) ) ) ,
101131 } ;
102132 } ,
103- Self :: View => {
104- match Self :: get_descriptions_and_statuses ( os) {
105- Ok ( entries) => {
106- if entries. is_empty ( ) {
107- execute ! ( session. stderr, style:: Print ( "No to-do lists to view" ) ) ?;
108- } else {
109- let selection = FuzzySelect :: new ( )
110- . with_prompt ( "Select task to view:" )
111- . items ( & entries)
112- . report ( false )
113- . interact_opt ( )
114- . unwrap_or ( None ) ;
115-
116- if let Some ( index) = selection {
117- if index < entries. len ( ) {
118- let list = match TodoState :: load ( os, & entries[ index] . id ) {
119- Ok ( list) => list,
120- Err ( _) => {
121- return Err ( ChatError :: Custom ( "Could not load requested to-do list" . into ( ) ) ) ;
122- }
123- } ;
124- match list. display_list ( & mut session. stderr ) {
125- Ok ( _) => { } ,
126- Err ( _) => {
127- return Err ( ChatError :: Custom ( "Could not display requested to-do list" . into ( ) ) ) ;
128- }
129- } ;
130- execute ! ( session. stderr, style:: Print ( "\n " ) , ) ?;
131- }
133+ Self :: View => match Self :: get_descriptions_and_statuses ( os) {
134+ Ok ( entries) => {
135+ if entries. is_empty ( ) {
136+ execute ! ( session. stderr, style:: Print ( "No to-do lists to view\n " ) ) ?;
137+ } else {
138+ let selection = FuzzySelect :: new ( )
139+ . with_prompt ( "Select a to-do list to view:" )
140+ . items ( & entries)
141+ . report ( false )
142+ . interact_opt ( )
143+ . unwrap_or ( None ) ;
144+
145+ if let Some ( index) = selection {
146+ if index < entries. len ( ) {
147+ let list = match TodoState :: load ( os, & entries[ index] . id ) {
148+ Ok ( list) => list,
149+ Err ( _) => {
150+ return Err ( ChatError :: Custom ( "Could not load requested to-do list" . into ( ) ) ) ;
151+ } ,
152+ } ;
153+ execute ! (
154+ session. stderr,
155+ style:: Print ( format!(
156+ "{} {}\n " ,
157+ "Viewing:" . magenta( ) ,
158+ entries[ index] . description. clone( )
159+ ) )
160+ ) ?;
161+ match list. display_list ( & mut session. stderr ) {
162+ Ok ( _) => { } ,
163+ Err ( _) => {
164+ return Err ( ChatError :: Custom ( "Could not display requested to-do list" . into ( ) ) ) ;
165+ } ,
166+ } ;
167+ execute ! ( session. stderr, style:: Print ( "\n " ) , ) ?;
132168 }
133169 }
134- } ,
135- Err ( _ ) => return Err ( ChatError :: Custom ( "Could not show to-do lists" . into ( ) ) ) ,
136- }
137- }
170+ }
171+ } ,
172+ Err ( _ ) => return Err ( ChatError :: Custom ( "Could not show to-do lists" . into ( ) ) ) ,
173+ } ,
138174 }
139175 Ok ( ChatState :: PromptUser {
140176 skip_printing_tools : true ,
@@ -155,7 +191,7 @@ impl TodoSubcommand {
155191 } ;
156192 // For some reason this doesn't work
157193 // Has to do with the Value::String wrapping in os.database.all_entries() rather than
158- // Value::from_str()
194+ // Value::from_str()
159195 // let temp_struct = match
160196 // serde_json::from_value::<TodoState>(value.clone()) { Ok(state) => state,
161197 // Err(_) => continue,
@@ -164,48 +200,50 @@ impl TodoSubcommand {
164200 out. push ( TodoDisplayEntry {
165201 num_completed : temp_struct. completed . iter ( ) . filter ( |b| * * b) . count ( ) ,
166202 num_tasks : temp_struct. completed . len ( ) ,
167- description : prewrap ( & temp_struct. task_description ) ,
203+ description : temp_struct. task_description ,
168204 id : id. clone ( ) ,
169205 } ) ;
170206 }
171207 Ok ( out)
172208 }
173209}
174210
175- const MAX_LINE_LENGTH : usize = 80 ;
176-
177- // FIX: Hacky workaround for cleanly wrapping lines
178- /// Insert newlines every n characters, not within a word and not at the end.
179- ///
180- /// Generated by Q
181- fn prewrap ( text : & str ) -> String {
182- if text. is_empty ( ) || MAX_LINE_LENGTH == 0 {
183- return text. to_string ( ) ;
184- }
185-
186- let mut result = String :: new ( ) ;
187- let mut current_line_length = 0 ;
188- let words: Vec < & str > = text. split_whitespace ( ) . collect ( ) ;
189-
190- for word in words. iter ( ) {
191- let word_length = word. len ( ) ;
192-
193- // If adding this word would exceed the line length and we're not at the start of a line
194- if current_line_length > 0 && current_line_length + 1 + word_length > MAX_LINE_LENGTH {
195- result. push ( '\n' ) ;
196- result. push_str ( & " " . repeat ( "> " . len ( ) ) ) ;
197- current_line_length = 0 ;
198- }
199-
200- // Add space before word if not at start of line
201- if current_line_length > 0 {
202- result. push ( ' ' ) ;
203- current_line_length += 1 ;
204- }
205-
206- result. push_str ( word) ;
207- current_line_length += word_length;
208- }
209-
210- result
211- }
211+ // const MAX_LINE_LENGTH: usize = 80;
212+
213+ // // FIX: Hacky workaround for cleanly wrapping lines
214+ // /// Insert newlines every n characters, not within a word and not at the end.
215+ // /// This function is very hacky and barely works (do not use).
216+ // ///
217+ // /// Generated by Q
218+ // ///
219+ // fn _prewrap(text: &str) -> String {
220+ // if text.is_empty() || MAX_LINE_LENGTH == 0 {
221+ // return text.to_string();
222+ // }
223+
224+ // let mut result = String::new();
225+ // let mut current_line_length = 0;
226+ // let words: Vec<&str> = text.split_whitespace().collect();
227+
228+ // for word in words.iter() {
229+ // let word_length = word.len();
230+
231+ // // If adding this word would exceed the line length and we're not at the start of a line
232+ // if current_line_length > 0 && current_line_length + 1 + word_length > MAX_LINE_LENGTH {
233+ // result.push('\n');
234+ // result.push_str(&" ".repeat("> ".len()));
235+ // current_line_length = 0;
236+ // }
237+
238+ // // Add space before word if not at start of line
239+ // if current_line_length > 0 {
240+ // result.push(' ');
241+ // current_line_length += 1;
242+ // }
243+
244+ // result.push_str(word);
245+ // current_line_length += word_length;
246+ // }
247+
248+ // result
249+ // }
0 commit comments