cmc/learn

My personal learning area.

clone: git clone https://gitbay.org/cmc/learn.git

main: rust/todo/src/main.rs · raw

  1use clap::{Arg, Command};
  2use std::fs::{self, OpenOptions};
  3use std::io::{self, Write};
  4use std::path::Path;
  5
  6#[derive(Debug)]
  7struct Task {
  8    id: usize,
  9    description: String,
 10    completed: bool,
 11}
 12
 13impl Task {
 14    fn to_string(&self) -> String {
 15        let status = if self.completed { "[X]" } else { "[ ]" };
 16        format!("{} {}", status, self.description)
 17    }
 18}
 19
 20fn main() {
 21    let matches = Command::new("Task Echo")
 22        .version("1.0")
 23        .about("Echoes tasks to a file")
 24        .arg(
 25            Arg::new("task")
 26                .short('t')
 27                .long("task")
 28                .value_name("TASK")
 29                .help("Sets the task to be saved")
 30                .num_args(1..),
 31        )
 32        .arg(
 33            Arg::new("done")
 34                .short('d')
 35                .long("done")
 36                .value_name("TASK_ID")
 37                .help("Marks the specified task(s) as complete")
 38                .num_args(1..),
 39        )
 40        .get_matches();
 41
 42    let file_path = "tasks.txt";
 43
 44    // Handle task completion
 45    if let Some(ids) = matches.get_many::<String>("done") {
 46        let mut tasks = load_tasks(file_path);
 47        let mut completed_tasks = Vec::new();
 48        for id in ids {
 49            if let Ok(index) = id.parse::<usize>() {
 50                if index > 0 && index <= tasks.len() {
 51                    tasks[index - 1].completed = true; // Mark task as complete
 52                } else {
 53                    completed_tasks.push(id.clone()); // Collect invalid task IDs
 54                }
 55            }
 56        }
 57        save_tasks(file_path, &tasks);
 58
 59        // Alert for nonexistent tasks
 60        if !completed_tasks.is_empty() {
 61            for id in completed_tasks {
 62                println!("Task {} doesn't exist.", id);
 63            }
 64        } else {
 65            println!("Tasks marked as complete.");
 66        }
 67
 68        // Display the updated task list
 69        display_tasks(file_path);
 70    }
 71
 72    // Handle new tasks
 73    if let Some(new_tasks) = matches.get_many::<String>("task") {
 74        let mut tasks = load_tasks(file_path);
 75        let next_id = tasks.len() + 1; // Determine the next task ID
 76        for task_desc in new_tasks {
 77            tasks.push(Task {
 78                id: next_id,
 79                description: task_desc.to_string(),
 80                completed: false,
 81            });
 82        }
 83        save_tasks(file_path, &tasks);
 84        println!("Tasks saved to {}", file_path);
 85
 86        // Display the updated task list
 87        display_tasks(file_path);
 88    }
 89
 90    // Display saved tasks if no new tasks or done tasks were provided
 91    if !matches.contains_id("task") && !matches.contains_id("done") {
 92        display_tasks(file_path);
 93    }
 94}
 95
 96fn load_tasks(file_path: &str) -> Vec<Task> {
 97    let mut tasks = Vec::new();
 98    if Path::new(file_path).exists() {
 99        let contents = fs::read_to_string(file_path).expect("Unable to read file");
100        for (id, line) in contents.lines().enumerate() {
101            let completed = line.starts_with("[X]");
102            let description = line[4..].trim().to_string();
103            tasks.push(Task {
104                id: id + 1,
105                description,
106                completed,
107            });
108        }
109    }
110    tasks
111}
112
113fn save_tasks(file_path: &str, tasks: &[Task]) {
114    let mut file = OpenOptions::new()
115        .create(true)
116        .write(true)
117        .truncate(true) // Clear the file before writing
118        .open(file_path)
119        .expect("Unable to open file");
120
121    for task in tasks {
122        writeln!(file, "{}", task.to_string()).expect("Unable to write to file");
123    }
124}
125
126fn display_tasks(file_path: &str) {
127    let tasks = load_tasks(file_path);
128    if tasks.is_empty() {
129        println!("No tasks saved yet.");
130    } else {
131        println!("Saved tasks:");
132        for task in tasks {
133            // Pad the task ID to a width of 3 for alignment
134            println!("{:>3}: {}", task.id, task.to_string()); // Display task ID
135        }
136    }
137}