A file-based task manager

ADD: show command, cleanup

+44 -14
+14 -1
src/main.rs
··· 86 full_id: bool, 87 }, 88 89 /// Drops the task on the top of the stack and archives it. 90 Drop, 91 ··· 187 Commands::Push { edit, body, title } => command_push(dir, edit, body, title), 188 Commands::List { all, count } => command_list(dir, all, count), 189 Commands::Swap => command_swap(dir), 190 Commands::Edit { task_id } => command_edit(dir, task_id), 191 Commands::Completion { shell } => command_completion(shell), 192 Commands::Drop => command_drop(dir), ··· 221 let mut body = body.unwrap_or_default(); 222 if body == "-" { 223 // add newline so you can type directly in the shell 224 - eprintln!(""); 225 body.clear(); 226 std::io::stdin().read_to_string(&mut body)?; 227 } ··· 314 fn command_reprioritize(dir: PathBuf, task_id: TaskId) -> Result<()> { 315 Workspace::from_path(dir)?.reprioritize(task_id.into()) 316 }
··· 86 full_id: bool, 87 }, 88 89 + Show { 90 + /// The [TSK-]ID of the task to display 91 + #[command(flatten)] 92 + task_id: TaskId, 93 + }, 94 + 95 /// Drops the task on the top of the stack and archives it. 96 Drop, 97 ··· 193 Commands::Push { edit, body, title } => command_push(dir, edit, body, title), 194 Commands::List { all, count } => command_list(dir, all, count), 195 Commands::Swap => command_swap(dir), 196 + Commands::Show { task_id } => command_show(dir, task_id), 197 Commands::Edit { task_id } => command_edit(dir, task_id), 198 Commands::Completion { shell } => command_completion(shell), 199 Commands::Drop => command_drop(dir), ··· 228 let mut body = body.unwrap_or_default(); 229 if body == "-" { 230 // add newline so you can type directly in the shell 231 + //eprintln!(""); 232 body.clear(); 233 std::io::stdin().read_to_string(&mut body)?; 234 } ··· 321 fn command_reprioritize(dir: PathBuf, task_id: TaskId) -> Result<()> { 322 Workspace::from_path(dir)?.reprioritize(task_id.into()) 323 } 324 + 325 + fn command_show(dir: PathBuf, task_id: TaskId) -> Result<()> { 326 + let task = Workspace::from_path(dir)?.task(task_id.into())?; 327 + println!("{task}"); 328 + Ok(()) 329 + }
+30 -13
src/workspace.rs
··· 157 drop(reader); 158 Ok(Task { 159 id, 160 - title, 161 - body, 162 file, 163 }) 164 } ··· 277 pub file: Flock<File>, 278 } 279 280 - /// A task container without a file handle 281 - pub struct BareTask { 282 - pub id: Id, 283 - pub title: String, 284 - pub body: String, 285 } 286 287 impl Task { ··· 295 Ok(()) 296 } 297 298 - fn bare(self) -> BareTask { 299 - BareTask { 300 id: self.id, 301 title: self.title, 302 body: self.body, ··· 304 } 305 } 306 307 - impl FromStr for BareTask { 308 type Err = Error; 309 310 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { ··· 322 } 323 } 324 325 - impl Display for BareTask { 326 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 327 write!( 328 f, ··· 340 } 341 342 impl<'a> Iterator for LazyTaskLoader<'a> { 343 - type Item = BareTask; 344 345 fn next(&mut self) -> Option<Self::Item> { 346 let stack_item = self.files.next()?; ··· 358 359 #[test] 360 fn test_bare_task_display() { 361 - let task = BareTask { 362 id: Id(123), 363 title: "Hello, world".to_string(), 364 body: "The body of the task.\nAnother line\r\nis here.".to_string(), ··· 367 "tsk-123\tHello, world\tThe body of the task. Another line is here.", 368 task.to_string() 369 ); 370 } 371 }
··· 157 drop(reader); 158 Ok(Task { 159 id, 160 + title: title.trim().to_string(), 161 + body: body.trim().to_string(), 162 file, 163 }) 164 } ··· 277 pub file: Flock<File>, 278 } 279 280 + impl Display for Task { 281 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 282 + write!(f, "{}\n\n{}", self.title, &self.body) 283 + } 284 } 285 286 impl Task { ··· 294 Ok(()) 295 } 296 297 + fn bare(self) -> SearchTask { 298 + SearchTask { 299 id: self.id, 300 title: self.title, 301 body: self.body, ··· 303 } 304 } 305 306 + /// A task container without a file handle 307 + pub struct SearchTask { 308 + pub id: Id, 309 + pub title: String, 310 + pub body: String, 311 + } 312 + 313 + impl FromStr for SearchTask { 314 type Err = Error; 315 316 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { ··· 328 } 329 } 330 331 + impl Display for SearchTask { 332 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 333 write!( 334 f, ··· 346 } 347 348 impl<'a> Iterator for LazyTaskLoader<'a> { 349 + type Item = SearchTask; 350 351 fn next(&mut self) -> Option<Self::Item> { 352 let stack_item = self.files.next()?; ··· 364 365 #[test] 366 fn test_bare_task_display() { 367 + let task = SearchTask { 368 id: Id(123), 369 title: "Hello, world".to_string(), 370 body: "The body of the task.\nAnother line\r\nis here.".to_string(), ··· 373 "tsk-123\tHello, world\tThe body of the task. Another line is here.", 374 task.to_string() 375 ); 376 + } 377 + 378 + #[test] 379 + fn test_task_display() { 380 + let task = Task { 381 + id: Id(123), 382 + title: "Hello, world".to_string(), 383 + body: "The body of the task.".to_string(), 384 + file: util::flopen("/dev/null".into(), FlockArg::LockShared).unwrap(), 385 + }; 386 + assert_eq!("Hello, world\n\nThe body of the task.", task.to_string()); 387 } 388 }