#!/usr/bin/env ruby $:.unshift File.dirname(__FILE__) + '/../lib' require 'rubygems' require 'commander/import' require 'pomo' program :version, Pomo::VERSION program :description, "Pomodoro time management. Most of the subcommands work directly with tasks, and because of this pomo provides a unified task selection api shown below which can be used with most of the commands (those with [task ...] in their synopsis). n : selects a single task by index : Ex: pomo remove 1 [n ]+ : selects several tasks by index : Ex: pomo remove 2 8 1 n..n : selects a range of tasks : Ex: pomo remove 5..9 n..-n : selects a range of tasks : Ex: pomo remove 2..-1 first : selects the first task : Ex: pomo remove first last : selects the last task : Ex: pomo remove last complete : selects complete tasks : Ex: pomo remove complete incomplete : selects incomplete tasks : Ex: pomo remove incomplete all : selects all tasks : Ex: pomo remove all " program :int_message, "\nTerminated pomo" \ "\n * previously running tasks not marked as complete" \ "\n * manually complete a task with `$ pomo complete `" list = Pomo::List.new File.exists?('.pomo') ? '.pomo' : '~/.pomo' default_command :list command :init do |c| c.syntax = 'pomo init [options]' c.description = 'Initialize pomo in the current directory' c.action do |args, options| Pomo::List.new '.pomo' say "Initialized at `./.pomo`" say " - Any commands run while in this directory will reference this file for tasks" say " - To remove simply execute `rm .pomo`" end end command :start do |c| c.syntax = 'pomo start [task] [options]' c.summary = 'Start a task' c.description = 'Start a task, given the task [task] or the first task' c.example 'Start the first task', 'pomo start' c.example 'Start the first task', 'pomo start 0' c.example 'Start the first task', 'pomo start first' c.example 'Start the fifth task', 'pomo start 5' c.action do |args, options| list.find(*args) do |task, i| abort 'task already completed' if task.complete? say "Started #{task}, you have #{task.length} minutes :)" task.start list.save break end end end command :import do |c| c.syntax = 'pomo import [options]' c.summary = 'Import Github project issues' c.description = 'Import Github project issues which have not yet been closed' c.action do |args, options| gem 'octopi', '>=0.2.1' require 'octopi' user = args.shift or raise('Github is required') project = args.shift or raise('Github is required') if repo = Octopi::Repository.find(:user => user, :name => project) say "Importing items from http://github.com/#{user}/#{project}" repo.issues.select { |i| not i.closed_at }.each do |issue| task = Pomo::GithubTask.new issue.title, :username => user, :project => project, :description => issue.body, :labels => issue.labels, :number => issue.number list << task say " - Added #{task}" end list.save end end end command :add do |c| c.syntax = 'pomo add [options]' c.summary = 'Add a task' c.description = 'Add a task to the current list of tasks' c.example 'Adds the task "fix IE styling issues"', 'pomo add "fix IE styling issues"' c.example 'Add a task with 60 minute limit', 'pomo add "create executable" --length 60' c.option '-d', '--description string', 'Add verbose task description' c.option '-l', '--length minutes', Integer, 'Change the default length in minutes' c.action do |args, options| task = Pomo::Task.new(args.shift, options.__hash__) list << task list.save say " - Added #{task}" end end command :edit do |c| c.syntax = 'pomo edit [task ...] [options]' c.summary = 'Edit tasks' c.description = 'Edit the given task(s) or the first task' c.example 'Changes the description for the first task', 'pomo edit first -d "fix IE styling issues"' c.example 'Changes the description and length for the third task', 'pomo edit 3 -d "fix IE styling issues" -l 60' c.example 'Changes the length of several tasks', 'pomo edit 1..5 -l 10' c.option '-n', '--name string', 'Change the task name' c.option '-d', '--description string', 'Change the task description' c.option '-l', '--length minutes', Integer, 'Change the task length' c.action do |args, options| list.find(*args) do |task, i| options.__hash__.each do |key, value| task.send :"#{key}=", value end say " - Updated #{task}" end list.save end end command :break do |c| c.syntax = 'pomo break [length] [options]' c.summary = 'Take a break' c.description = 'Take a break, defaults to 5 minutes or [length] or --length' c.example 'Take a five minute break', 'pomo break' c.example 'Take a 30 minute break', 'pomo break 30' c.example 'Take a 30 minute break', 'pomo break --length 30' c.option '-l', '--length minutes', Integer, 'Change the default length in minutes' c.action do |args, options| options.default :length => args.first ? args.first.to_i : 5 task = Pomo::Task.new('Break time', options.__hash__) task.start end end command :remove do |c| c.syntax = 'pomo [remove|rm] [task ...] [options]' c.summary = 'Remove tasks' c.description = 'Remove task(s) or the first task' c.example 'Remove the first task', 'pomo remove first' c.example 'Remove the last task', 'pomo remove last' c.example 'Remove the fifth task', 'pomo remove 5' c.example 'Remove the fifth and second task', 'pomo rm 5 2' c.example 'Remove a range of tasks', 'pomo rm 2..6' c.example 'Remove all but the first task', 'pomo rm 2..-1' c.example 'Remove all tasks', 'pomo rm all' c.action do |args, options| list.find(*args) do |task, i| list.tasks -= [task] say " - Removed #{task}" end list.save end end alias_command :rm, :remove alias_command :clear, :remove, 'all' command :view do |c| c.syntax = 'pomo view [task ...] [options]' c.summary = 'View verbose task information' c.description = 'View verbose information for the given task(s) or the first task' c.example 'View the first task', 'pomo view first' c.example 'View the last task', 'pomo view last' c.example 'View the fifth task', 'pomo view 5' c.action do |args, options| list.find(*args) do |task, i| say "\n" format = "%15s : %s\n" say format % ['name', task.name] say format % ['length', "#{task.length} minutes"] say format % ['description', task.description] if task.description and not task.description.empty? if task.github? say format % ['labels', task.labels.join(', ')] if task.labels and not task.labels.empty? say format % ['number', task.number ] say format % ['uri', task.uri ] end end say "\n" end end command :complete do |c| c.syntax = 'pomo complete [task ...] [options]' c.summary = 'Mark tasks as completed' c.description = 'Mark the given task(s) or the first task to complete' c.example 'Mark first task as complete', 'pomo complete first' c.example 'Mark last task as complete', 'pomo complete last' c.example 'Mark fifth task as complete', 'pomo complete 5' c.action do |args, options| list.find(*args) do |task, i| task.complete = true say " - Completed #{task}" end list.save end end command :incomplete do |c| c.syntax = 'pomo incomplete [task ...] [options]' c.summary = 'Mark tasks as incompleted' c.description = 'Mark the given task(s) or the first task as not completed' c.example 'Mark first task as not completed', 'pomo incomplete first' c.example 'Mark last task as not completed', 'pomo incomplete last' c.example 'Mark fifth task as not completed', 'pomo incomplete 5' c.action do |args, options| list.find(*args) do |task, i| task.complete = false say " - #{task} marked incomplete" end list.save end end command :list do |c| c.syntax = 'pomo list [options]' c.description = 'List all tasks' c.example 'List all tasks', 'pomo list' c.option '-c', '--complete', 'List only completed tasks' c.option '-i', '--incomplete', 'List only incompleted tasks' c.action do |args, options| total = 0 list.tasks.each_with_index do |task, i| next if options.complete && !task.complete? next if options.incomplete && task.complete? say ' %s %2d. %-45s : %d minutes' % [task.complete? ? '✓' : ' ', i, task.to_s, task.length] total += task.length end say ' ' * 55 + '%d minutes' % total end end