todo_cli_app/
lib.rs

1use anyhow::{Context, Result};
2use clap::{Parser, Subcommand};
3use std::fs::File;
4use std::fs::OpenOptions;
5use std::io::{BufRead, BufReader};
6
7/// A fictional versioning CLI
8#[derive(Debug, Parser)] // requires `derive` feature
9#[command(name = "todo-cli-app")]
10#[command(about = "Yet another todo CLI app written in Rust", long_about = None)]
11pub struct Cli {
12    /// The path to the file to read/write!
13    #[arg(short, long)]
14    pub file: Option<String>,
15    #[command(subcommand)]
16    pub command: Commands,
17}
18
19#[derive(Debug, Subcommand)]
20pub enum Commands {
21    /// Initialize a new todo file
22    Init { path: Option<String> },
23
24    /// add tasks
25    Add { task: String },
26
27    /// remove tasks
28    RM { number: usize },
29
30    /// list tasks
31    List {},
32
33    /// complete tasks
34    Done { number: usize },
35
36    /// clear all tasks
37    Clear {},
38
39    /// sort tasks
40    SORT {},
41
42    /// edit a task
43    EDIT { number: usize },
44
45    /// add tags for the tasks sync from other device
46    SYNC {},
47
48    /// remove finished tasks
49    CLEAN {},
50}
51
52pub fn check_file(file_path: &str) -> Result<File> {
53    let todofile = OpenOptions::new()
54        .create(true)
55        .append(true)
56        .open(file_path)
57        .with_context(|| format!("Failed to open or create file: {}", file_path))?;
58
59    Ok(todofile)
60}
61
62pub fn read_line(path: &str, target_string: &str) -> Option<u32> {
63    let file = BufReader::new(File::open(path).expect("Unable to open file"));
64    let mut current_line_number = 1;
65
66    for line in file.lines() {
67        current_line_number += 1;
68
69        if let Ok(content) = line {
70            if content.contains(target_string) {
71                return Some(current_line_number);
72            }
73        }
74    }
75    if current_line_number == 0 {
76        return Some(0);
77    } else {
78        return Some(current_line_number);
79    }
80}