Skip to content

Instantly share code, notes, and snippets.

@BrainMaestro
Created February 14, 2017 07:39
Show Gist options
  • Save BrainMaestro/f08e38c561e71e7dc10172c64586fc8b to your computer and use it in GitHub Desktop.
Save BrainMaestro/f08e38c561e71e7dc10172c64586fc8b to your computer and use it in GitHub Desktop.
Terminal todo application in Rust
use std::{fmt, io};
struct TodoItem {
id: usize,
title: String,
completed: bool,
deleted: bool,
}
struct TodoList {
items: Vec<TodoItem>
}
enum Operation {
Complete,
Toggle,
Delete,
}
impl TodoItem {
fn new(id: usize, title: &str) -> Self {
TodoItem {
id: id,
title: title.to_string(),
completed: false,
deleted: false,
}
}
fn toggle(&mut self, done: Option<bool>) {
match done {
None => self.completed = !self.completed,
Some(done) => self.completed = done,
}
}
fn delete(&mut self) {
self.deleted = true;
}
}
impl TodoList {
fn new() -> Self {
TodoList { items: Vec::<TodoItem>::new() }
}
fn add_item(&mut self, title: &str) {
let len = self.items.len() + 1;
if title != "" { self.items.push(TodoItem::new(len, title)) }
}
fn find_item(&mut self, index: Option<usize>, title: Option<&str>, operation: &Operation) {
let todo = if let Some(id) = index {
self.items.iter_mut().find(|ref item| item.id == id)
} else if let Some(title) = title {
self.items.iter_mut().find(|ref item| item.title == title)
} else {
None
};
if let Some(todo) = todo {
match *operation {
Operation::Complete => todo.toggle(Some(true)),
Operation::Toggle => todo.toggle(None),
Operation::Delete => todo.delete(),
}
}
}
}
impl fmt::Display for TodoItem {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let done = if self.completed { "✔" } else { " " };
write!(f, "[{}] - {}. {}", done, self.id, self.title)
}
}
impl fmt::Display for TodoList {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut output = String::new();
for item in &self.items {
if !item.deleted { output.push_str(&format!("{}\n", item)) }
}
write!(f, "{}", output)
}
}
fn main() {
let mut todo_list = TodoList::new();
println!("Todo List\n=========");
loop {
let mut command = String::new();
println!("{}", todo_list);
io::stdin()
.read_line(&mut command)
.expect("failed to read line");
let input: Vec<&str> = command.split_whitespace().collect();
let command = input[0];
let todo_string = input[1..].join(" ");
let todos: Vec<&str> = todo_string.split(|c| c == ';' || c == ',').collect();
match command {
"a" | "-a" | "add" | "--add" => for todo in todos { todo_list.add_item(todo.trim()); },
"c" | "-c" | "complete" | "--complete" => find_all(&mut todo_list, todos, Operation::Complete),
"t" | "-t" | "toggle" | "--toggle" => find_all(&mut todo_list, todos, Operation::Toggle),
"d" | "-d" | "delete" | "--delete" => find_all(&mut todo_list, todos, Operation::Delete),
"h" | "-h" | "help" | "--help" => print_help(),
"exit" | "q" | "quit" => break,
_ => println!("Invalid command: `{}`\nType 'h' or 'help' for help", command),
}
}
}
fn find_all(todo_list: &mut TodoList, todos: Vec<&str>, operation: Operation) {
for todo in todos {
let todo_string = todo.trim();
let (index, title) = match todo_string.parse::<usize>() {
Ok(index) if index <= todo_list.items.len() => (Some(index), None),
Ok(_) | Err(_) if todo_string != "" => (None, Some(todo_string)),
_ => (None, None)
};
todo_list.find_item(index, title, &operation);
}
}
fn print_help() {
println!("Usage: [options] [, separated list of arguments]");
println!("a, add \t\t\t Add new todo items");
println!("c, complete \t\t Complete todo items");
println!("t, toggle \t\t Toggle todo items");
println!("d, delete \t\t Delete todo items");
println!("============================================");
println!("h, help \t\t Help");
println!("q, quit \t\t Quit");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment