Skip to content

Instantly share code, notes, and snippets.

@kdwinter
Created March 9, 2009 17:50
Show Gist options
  • Save kdwinter/76395 to your computer and use it in GitHub Desktop.
Save kdwinter/76395 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby19
# encoding: utf-8
=begin
Author: Gigamo <gigamo@gmail.com>
Inspired by Todo.txt (http://www.todotxt.com)
Usage: rudo <action> [<action arguments>]
* rudo add <some text>
* rudo del <tasknumber>
* rudo prioritize <tasknumber> [{A|B|C|X|''}]
* rudo append <tasknumber> [<some text to append>]
* rudo replace <tasknumber> [<some text to replace>]
* rudo list [<match>]
=end
module Rudo
extend self
# File that stores the todo items.
@todo_file = ENV["HOME"] + '/.todotxt/todo.txt'
# Main method.
def run
# Check if @todo_file exists, exit if not.
die "[+] #@todo_file doesn't exist" unless File.exists? @todo_file
# Create a new Todo instance
todo = Todo.new(@todo_file)
# Parse commandline input.
case ARGV.shift
when 'add'
todo.add(ARGV.join(' ')) unless ARGV.empty?
when 'rm', 'del', 'delete'
todo.delete(ARGV.shift.to_i) if ARGV.length == 1
when 'prio', 'prioritize'
todo.prioritize(ARGV.shift.to_i, ARGV[0].nil? ? '' : ARGV[0])
when 'append'
todo.append(ARGV.shift.to_i, ARGV.join(' ')) unless ARGV.length < 1
when 'mv', 'replace'
todo.replace(ARGV.shift.to_i, ARGV.join(' ')) unless ARGV.length < 1
when 'ls', 'list'
ARGV.empty? ? todo.list : todo.list(ARGV)
else
puts help
end
end
class Todo
attr_reader :file
def initialize(file)
@file = file
end
def add(text)
# Add a new task to @todo_file.
File.open(self.file, 'a') { |file| file.puts text }
line = IO.readlines(self.file).count.to_i
puts "[+] Added `#{text}' at line #{line}"
end
def append(item, text='')
# Append text to an existing task.
tasks = get_tasks
Rudo.die "[+] #{item}: No such todo." unless tasks.has_key? item
orig_text = tasks[item]
tasks[item] = [tasks[item], text].join(' ')
write_tasks tasks
puts "[+] Appended `#{text}' to `#{orig_text}'"
end
def replace(item, text)
# Replace text in a given task.
tasks = get_tasks
Rudo.die "[+] #{item}: No such todo." unless tasks.has_key? item
orig_text = tasks[item]
tasks[item] = text
puts "[+] Replaced `#{orig_text}' with `#{text}'"
write_tasks tasks
end
def delete(item)
# Delete a task by given tasknumber.
tasks = get_tasks
Rudo.die "[+] #{item}: No such todo." unless tasks.has_key? item
orig_task = tasks[item]
puts "[+] Delete `#{tasks[item]}' [y/n]?"
case $stdin.gets.chomp
when 'y', 'yes', 'yeah', 'yup', 'yep'
tasks.delete(item)
puts "[+] Deleted `#{orig_task}'"
end
write_tasks tasks
end
def list(patterns=nil)
# Print a list of all tasks found in @todo_file.
# Optionally accept arguments, match arguments for
# items in the list, and print only matching items.
items = []
tasks = get_tasks
if patterns
tasks.each do |key, value|
match = true
patterns.each { |pattern| match = false unless value[/#{pattern}/i] }
items << "#{key}: #{value}" if match
end
else
tasks.each { |key, value| items << "#{key}: #{value}" }
end
re_pri = /.*(\([A-Z]\)).*/
items.sort.each { |item| puts item.sub(re_pri, highlight_priority(item)) }
tasks[items.size].length.times { print '-' }
puts "---\nListing #{items.size} #{items.size == 1 ? 'item' : 'items'}."
end
def prioritize(item, prio='')
# Prioritize tasks by A, B, C, X or ''
prio = prio.upcase
tasks = get_tasks
Rudo.die "[+] #{item}: No such todo." unless tasks.has_key? item
Rudo.die "[+] #{prio}: Not recognized" unless prio[/[A-Z]/] || prio == ''
re_pri = /\([A-Z]?\) /
orig_task = tasks[item].sub(re_pri, '')
if prio == ''
tasks[item] = tasks[item].sub(re_pri, '')
elsif tasks[item][re_pri]
tasks[item] = tasks[item].gsub(re_pri, "(#{prio}) ")
else
tasks[item] = "(#{prio}) #{tasks[item]}"
end
puts "[+] Prioritized `#{orig_task}' with `#{prio == '' ? 'nothing' : prio}'"
write_tasks tasks
end
private
def get_tasks
# Get a hash of tasks from @todo_file.
count = 0
tasks = {}
File.open(self.file).each_line do |line|
next if line.strip == ''
count += 1
tasks[count] = line.chomp
end.close
return tasks
end
def write_tasks(task_dict)
# Write a dictionary of tasks to @todo_file.
keys = task_dict.keys.sort
File.open(self.file, 'w') do |file|
keys.each { |key| file.puts task_dict[key] }
end
end
def highlight_priority(matchobject)
# Colorize list's output by priority
yellow = "\033[0;33m"
green = "\033[0;32m"
magenta = "\033[0;35m"
white = "\033[0;37m"
default = "\033[0m"
case matchobject.split[1]
when '(A)'
return yellow << matchobject << default
when '(B)'
return green << matchobject << default
when '(C)'
return magenta << matchobject << default
else
return white << matchobject << default
end
end
end
def die(text)
# Print error and exit.
$stderr.puts text
exit 1
end
private
def help
# Return usage located in the comments above.
return "Usage: " + File.read(__FILE__).match(/Usage:(.+?)=end/m)[1].strip.gsub(/rudo/, File.basename($0))
end
end
Rudo.run if $0 == __FILE__
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment