todotxt 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +6 -14
- data/.gitignore +2 -0
- data/README.md +40 -18
- data/Rakefile +1 -4
- data/bin/todotxt +5 -5
- data/features/edit.feature +1 -1
- data/features/files.feature +53 -0
- data/features/initialize.feature +0 -11
- data/features/move.feature +13 -0
- data/features/step_definitions/environment_steps.rb +8 -4
- data/features/step_definitions/list_steps.rb +5 -1
- data/lib/todotxt.rb +9 -8
- data/lib/todotxt/cli.rb +96 -142
- data/lib/todotxt/clihelpers.rb +21 -24
- data/lib/todotxt/config.rb +45 -16
- data/lib/todotxt/regex.rb +5 -5
- data/lib/todotxt/todo.rb +44 -30
- data/lib/todotxt/todofile.rb +11 -11
- data/lib/todotxt/todolist.rb +31 -19
- data/lib/todotxt/version.rb +1 -1
- data/spec/config_spec.rb +41 -21
- data/spec/fixtures/config_no_todo.cfg +2 -0
- data/spec/todo_spec.rb +77 -90
- data/spec/todofile_spec.rb +17 -12
- data/spec/todolist_spec.rb +65 -66
- data/todotxt.gemspec +19 -21
- metadata +50 -61
    
        checksums.yaml
    CHANGED
    
    | @@ -1,15 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 | 
            -
             | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
              metadata.gz: !binary |-
         | 
| 9 | 
            -
                ZGU5YTU3YjIwNmU3YTNmNzg4ZTlhNDczMmJjZGI5YTE2OTFkY2JmYTM3MDNm
         | 
| 10 | 
            -
                MTBhNjliYThhOTk4YjdmODM1ZGM4MTEyYmQwNzRkMDU0Y2IzNjVjMTg3YjBh
         | 
| 11 | 
            -
                ZTdiZDIyMjZiODg3YjAzMzRhZmM0YjdjNGFkYzZmNjA4Y2JlOTI=
         | 
| 12 | 
            -
              data.tar.gz: !binary |-
         | 
| 13 | 
            -
                MjFiMTU5YzIxNjMxMTZlZTlhZmIxYTRmZmFkMTAzMzY3NmM2OGQ2NDJjYWY3
         | 
| 14 | 
            -
                N2ExMDgwZThjMGJhODk0NmJmNTM5Nzc0N2IxNTJiMWM1ODcwYzY5ZjFlMDAy
         | 
| 15 | 
            -
                NWI0MmEwNjcxMzNmMDJlNjZlMWY4ZTM1NGEwNGQwOWEyZDU2YjA=
         | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: 21a772c6a03508479892cd47bd8b75e9d6161a369340d9d42991ffac17c18267
         | 
| 4 | 
            +
              data.tar.gz: 9f8ee70e7841c6684360964dbcd3dfc23be934fdcfc314160073d5dda66244cf
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: f6fc1646f58339be5635fb1021301374dbb4a524de107b0689c3910cadffcf757e392de8c7aa61e4745ecb82425f00acd70f5f128a7b393597cfd9a6a1f92249
         | 
| 7 | 
            +
              data.tar.gz: 1f180c48442d392b95b6875fe27d4cd8fd8f6941c4825a4c38be05d3343cdf5c77ff4e809900846ee7c7f5cbb7550225cc94dfdcff7c1b813fd8a253d90e5d21
         | 
    
        data/.gitignore
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -38,27 +38,49 @@ The gem will install a command, `todotxt` which is used to interact with your | |
| 38 38 | 
             
            todo.txt.
         | 
| 39 39 |  | 
| 40 40 | 
             
                Tasks:
         | 
| 41 | 
            -
                  todotxt add | a TEXT | 
| 42 | 
            -
                  todotxt append | app ITEM# STRING | 
| 43 | 
            -
                  todotxt del | rm ITEM#[, ITEM#, ITEM#, ...] | 
| 44 | 
            -
                  todotxt do ITEM#[, ITEM#, ITEM#, ...] | 
| 45 | 
            -
                  todotxt dp | depri ITEM#[, ITEM#, ITEM#, ...] | 
| 46 | 
            -
                  todotxt  | 
| 47 | 
            -
                  todotxt  | 
| 48 | 
            -
                  todotxt generate_config | 
| 49 | 
            -
                  todotxt  | 
| 50 | 
            -
                  todotxt  | 
| 51 | 
            -
                  todotxt  | 
| 52 | 
            -
                  todotxt  | 
| 53 | 
            -
                  todotxt  | 
| 54 | 
            -
                  todotxt  | 
| 55 | 
            -
                  todotxt  | 
| 56 | 
            -
                  todotxt  | 
| 57 | 
            -
                  todotxt  | 
| 58 | 
            -
                  todotxt  | 
| 41 | 
            +
                  todotxt add | a TEXT                               # Add a new Todo item
         | 
| 42 | 
            +
                  todotxt append | app ITEM# STRING                  # Append STRING to ITEM#
         | 
| 43 | 
            +
                  todotxt del | rm ITEM#[, ITEM#, ITEM#, ...]        # Remove ITEM#
         | 
| 44 | 
            +
                  todotxt do ITEM#[, ITEM#, ITEM#, ...]              # Mark ITEM# as done
         | 
| 45 | 
            +
                  todotxt dp | depri ITEM#[, ITEM#, ITEM#, ...]      # Remove priority for ITEM#
         | 
| 46 | 
            +
                  todotxt due                                        # List due items
         | 
| 47 | 
            +
                  todotxt edit                                       # Open todo.txt file in your default editor
         | 
| 48 | 
            +
                  todotxt generate_config                            # Create a .todotxt.cfg file in your home folder, containing the path to todo.txt
         | 
| 49 | 
            +
                  todotxt generate_txt                               # Create a sample todo.txt
         | 
| 50 | 
            +
                  todotxt help [TASK]                                # Describe available tasks or one specific task
         | 
| 51 | 
            +
                  todotxt list | ls [SEARCH]                         # List all todos, or todos matching SEARCH
         | 
| 52 | 
            +
                  todotxt listproj | lsproj                          # List all projects
         | 
| 53 | 
            +
                  todotxt lscon | lsc                                # List all contexts
         | 
| 54 | 
            +
                  todotxt lsdone | lsd                               # List all done items
         | 
| 55 | 
            +
                  todotxt move | mv ITEM#[, ITEM#, ITEM#, ...] file  # Move ITEM# to another file
         | 
| 56 | 
            +
                  todotxt prepend | prep ITEM# STRING                # Prepend STRING to ITEM#
         | 
| 57 | 
            +
                  todotxt pri | p ITEM# PRIORITY                     # Set priority of ITEM# to PRIORITY
         | 
| 58 | 
            +
                  todotxt replace ITEM# TEXT                         # Completely replace ITEM# text with TEXT
         | 
| 59 | 
            +
                  todotxt undo | u ITEM#[, ITEM#, ITEM#, ...]        # Mark ITEM# item as not done
         | 
| 60 | 
            +
                  todotxt version                                    # Show todotxt version
         | 
| 59 61 |  | 
| 60 62 | 
             
            Calling simply `todotxt` will automatically run the `ls` command.
         | 
| 61 63 |  | 
| 64 | 
            +
            You can pass the option `--file=` to point todotxt to another file. You
         | 
| 65 | 
            +
            can pass an alias, defined in the configuration, or the path to an
         | 
| 66 | 
            +
            arbitrary file.
         | 
| 67 | 
            +
             | 
| 68 | 
            +
            With a file wishlist, in the configuration defined as "wishlist", you
         | 
| 69 | 
            +
            can run:
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                todotxt ls --file=wishlist
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            To list all items form this wishlist file. Alternatively you can run:
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                todotxt ls --file="~/Dropbox/todo/deferred.txt"
         | 
| 76 | 
            +
             | 
| 77 | 
            +
            To list all items from the file deferred.txt, provided that file
         | 
| 78 | 
            +
            exists.
         | 
| 79 | 
            +
             | 
| 80 | 
            +
            In order to list all items from all files defined in the config, use the
         | 
| 81 | 
            +
            `--all` flag with ls:
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                todotxt ls --all
         | 
| 62 84 |  | 
| 63 85 | 
             
            ## Screenshot
         | 
| 64 86 |  | 
    
        data/Rakefile
    CHANGED
    
    
    
        data/bin/todotxt
    CHANGED
    
    | @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            #!/usr/bin/env ruby
         | 
| 2 2 |  | 
| 3 | 
            -
            libdir = File.join(File.dirname(File.dirname(__FILE__)),  | 
| 3 | 
            +
            libdir = File.join(File.dirname(File.dirname(__FILE__)), 'lib')
         | 
| 4 4 | 
             
            $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
         | 
| 5 5 |  | 
| 6 6 | 
             
            args = ARGV.clone
         | 
| 7 7 |  | 
| 8 | 
            -
            #if args.empty?
         | 
| 9 | 
            -
             | 
| 10 | 
            -
            #end
         | 
| 8 | 
            +
            # if args.empty?
         | 
| 9 | 
            +
            # args.push "ls"
         | 
| 10 | 
            +
            # end
         | 
| 11 11 |  | 
| 12 | 
            -
            require  | 
| 12 | 
            +
            require 'todotxt'
         | 
| 13 13 | 
             
            Todotxt::CLI.start(args)
         | 
    
        data/features/edit.feature
    CHANGED
    
    | @@ -13,7 +13,7 @@ Feature: Edit | |
| 13 13 | 
             
                  | 2012-12-12 Buy GTD book @amazon +wishlist |
         | 
| 14 14 |  | 
| 15 15 | 
             
              Scenario: Open the file in the systems editor
         | 
| 16 | 
            -
                Given the  | 
| 16 | 
            +
                Given the environment variable "EDITOR" is set to "echo"
         | 
| 17 17 | 
             
                And a default config exists
         | 
| 18 18 | 
             
                When I run `todotxt edit`
         | 
| 19 19 | 
             
                Then it should pass with:
         | 
| @@ -0,0 +1,53 @@ | |
| 1 | 
            +
            Feature: Files
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              So that I can organise my Todo-items better
         | 
| 4 | 
            +
              As a user
         | 
| 5 | 
            +
              I want to use different files
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              Background:
         | 
| 8 | 
            +
                Given a config exists with the following files:
         | 
| 9 | 
            +
                  | alias    | path         |
         | 
| 10 | 
            +
                  | todo     | todo.txt     | 
         | 
| 11 | 
            +
                  | wishlist | wishlist.txt | 
         | 
| 12 | 
            +
                And a todofile with the following items exists:
         | 
| 13 | 
            +
                  | todo                     | 
         | 
| 14 | 
            +
                  | Read book on GTD         | 
         | 
| 15 | 
            +
                  | Publish wishlist on site | 
         | 
| 16 | 
            +
                And a todofile named "wishlist.txt" with the following items exists:
         | 
| 17 | 
            +
                  | todo                               |
         | 
| 18 | 
            +
                  | Getting Things Done @bookstore     |
         | 
| 19 | 
            +
                  | Label Maker @officesupply          |
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              Scenario: Run list with --files option
         | 
| 22 | 
            +
                When I run `todotxt list --file=wishlist`
         | 
| 23 | 
            +
                Then it should pass with:
         | 
| 24 | 
            +
                  """
         | 
| 25 | 
            +
                  Getting Things Done @bookstore
         | 
| 26 | 
            +
                  """
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              Scenario: Provide a file that is not in the config
         | 
| 29 | 
            +
                When I run `todotxt list --file=doesnotexist` interactively
         | 
| 30 | 
            +
                Then it should fail with:
         | 
| 31 | 
            +
                  """
         | 
| 32 | 
            +
                  \"doesnotexist\" is not defined in the config
         | 
| 33 | 
            +
                  """
         | 
| 34 | 
            +
             | 
| 35 | 
            +
              Scenario: Run list with --files option and a filename for a file not in the config
         | 
| 36 | 
            +
                Given a todofile named "deferred.txt" with the following items exists:
         | 
| 37 | 
            +
                  | todo                               |
         | 
| 38 | 
            +
                  | Getting Things Done @bookstore     |
         | 
| 39 | 
            +
                When I run `todotxt list --file=./deferred.txt`
         | 
| 40 | 
            +
                Then it should pass with:
         | 
| 41 | 
            +
                  """
         | 
| 42 | 
            +
                  Getting Things Done @bookstore
         | 
| 43 | 
            +
                  """
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              Scenario: List entries from all files
         | 
| 46 | 
            +
                When I run `todotxt list --all`
         | 
| 47 | 
            +
                Then it should pass with:
         | 
| 48 | 
            +
                  """
         | 
| 49 | 
            +
                  1. Read book on GTD
         | 
| 50 | 
            +
                  2. Publish wishlist on site
         | 
| 51 | 
            +
                  3. Getting Things Done @bookstore
         | 
| 52 | 
            +
                  4. Label Maker @officesupply
         | 
| 53 | 
            +
                  """
         | 
    
        data/features/initialize.feature
    CHANGED
    
    | @@ -60,14 +60,3 @@ Feature: Initialize | |
| 60 60 | 
             
                When I run `todotxt` interactively
         | 
| 61 61 | 
             
                And I type "no"
         | 
| 62 62 | 
             
                Then a file named "todo.txt" should not exist
         | 
| 63 | 
            -
             | 
| 64 | 
            -
              Scenario: Running with an old config-file still works
         | 
| 65 | 
            -
                Given an old config exists
         | 
| 66 | 
            -
                And a todofile with the following items exists:
         | 
| 67 | 
            -
                   | todo                  | 
         | 
| 68 | 
            -
                   | Update my config file | 
         | 
| 69 | 
            -
                When I run `todotxt`
         | 
| 70 | 
            -
                Then it should pass with:
         | 
| 71 | 
            -
                  """
         | 
| 72 | 
            -
                  1. Update my config file
         | 
| 73 | 
            -
                  """
         | 
    
        data/features/move.feature
    CHANGED
    
    | @@ -25,6 +25,19 @@ Feature: move | |
| 25 25 | 
             
                And the file "todo.txt" should not contain "Getting Things Done @bookstore"
         | 
| 26 26 | 
             
                And the file "wishlist.txt" should contain "Getting Things Done @bookstore"
         | 
| 27 27 |  | 
| 28 | 
            +
              Scenario: Move an item from wishlist.txt to todo.txt
         | 
| 29 | 
            +
                Given a todofile named "wishlist.txt" with the following items exists:
         | 
| 30 | 
            +
                   | todo                   |
         | 
| 31 | 
            +
                   | x Archive todotxt @gtd |
         | 
| 32 | 
            +
                When I run `todotxt move 1 todo --file=wishlist`
         | 
| 33 | 
            +
                Then it should pass with:
         | 
| 34 | 
            +
                  """
         | 
| 35 | 
            +
                  1. x Archive todotxt @gtd
         | 
| 36 | 
            +
                  => Moved to todo.txt
         | 
| 37 | 
            +
                  """
         | 
| 38 | 
            +
                And the file "wishlist.txt" should not contain "x Archive todotxt @gtd"
         | 
| 39 | 
            +
                And the file "todo.txt" should contain "x Archive todotxt @gtd"
         | 
| 40 | 
            +
             | 
| 28 41 | 
             
              Scenario: Move an illegal item
         | 
| 29 42 | 
             
                When I run `todotxt move 1337 wishlist`
         | 
| 30 43 | 
             
                Then it should pass with:
         | 
| @@ -29,19 +29,23 @@ Given /^a todofile with done items exists$/ do | |
| 29 29 | 
             
              write_file("todo.txt", "Read documentation for todotxt\nx Install todotxt\nWrite cucumber steps for todotxt")
         | 
| 30 30 | 
             
            end
         | 
| 31 31 |  | 
| 32 | 
            -
            Given /^a todofile with the following items exists:$/ do |todolist|
         | 
| 32 | 
            +
            Given /^a todofile named "(.*?)" with the following items exists:$/ do |filename, todolist|
         | 
| 33 33 | 
             
              contents = todolist.hashes.map {|row| row["todo"] }.join("\n")
         | 
| 34 | 
            -
              write_file( | 
| 34 | 
            +
              write_file(filename, contents)
         | 
| 35 | 
            +
            end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            Given /^a todofile with the following items exists:$/ do |todolist|
         | 
| 38 | 
            +
              step %{a todofile named "todo.txt" with the following items exists:}, todolist
         | 
| 35 39 | 
             
            end
         | 
| 36 40 |  | 
| 37 41 | 
             
            Given /^an empty todofile named "(.*?)" exists$/ do |filename|
         | 
| 38 42 | 
             
              write_file(filename, "")
         | 
| 39 43 | 
             
            end
         | 
| 40 44 |  | 
| 41 | 
            -
            Given /^the  | 
| 45 | 
            +
            Given /^the environment variable "(.*?)" is set to "(.*?)"$/ do |name, value|
         | 
| 42 46 | 
             
              ENV[name] = value
         | 
| 43 47 | 
             
            end
         | 
| 44 48 |  | 
| 45 49 | 
             
            Given /^the date is "(.*?)"$/ do |date|
         | 
| 46 | 
            -
              step %{the  | 
| 50 | 
            +
              step %{the environment variable "date" is set to "#{date}"}
         | 
| 47 51 | 
             
            end
         | 
| @@ -1,6 +1,10 @@ | |
| 1 1 | 
             
            Then /^I should see all entries from the todofile with numbers$/ do
         | 
| 2 | 
            +
              step %{I should see all entries from the todofile named "todo.txt" with numbers}
         | 
| 3 | 
            +
            end
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Then /^I should see all entries from the todofile named "([^"]*)" with numbers$/ do |filename|
         | 
| 2 6 | 
             
              contents = ""
         | 
| 3 | 
            -
              File.open(File.join(ENV["HOME"],  | 
| 7 | 
            +
              File.open(File.join(ENV["HOME"], filename)).each_line do |line|
         | 
| 4 8 | 
             
                # matching "1. Do Something"
         | 
| 5 9 | 
             
                contents += "([\\d]\.\\s+)#{Regexp.escape(line.strip)}.*"
         | 
| 6 10 | 
             
              end
         | 
    
        data/lib/todotxt.rb
    CHANGED
    
    | @@ -2,14 +2,15 @@ | |
| 2 2 | 
             
            libdir = File.dirname(__FILE__)
         | 
| 3 3 | 
             
            $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
         | 
| 4 4 |  | 
| 5 | 
            +
            # Todotxt is a Ruby librairy / CLI interface to work with [todo.txt](http://www.todotxt.com) format files.
         | 
| 5 6 | 
             
            module Todotxt
         | 
| 6 | 
            -
              autoload :Todo,        | 
| 7 | 
            -
              autoload :TodoList,    | 
| 8 | 
            -
              autoload :TodoFile,    | 
| 9 | 
            -
              autoload :CLI,         | 
| 10 | 
            -
              autoload :CLIHelpers,  | 
| 11 | 
            -
              autoload :Config,      | 
| 7 | 
            +
              autoload :Todo,       'todotxt/todo'
         | 
| 8 | 
            +
              autoload :TodoList,   'todotxt/todolist'
         | 
| 9 | 
            +
              autoload :TodoFile,   'todotxt/todofile'
         | 
| 10 | 
            +
              autoload :CLI,        'todotxt/cli'
         | 
| 11 | 
            +
              autoload :CLIHelpers, 'todotxt/clihelpers'
         | 
| 12 | 
            +
              autoload :Config,     'todotxt/config'
         | 
| 12 13 | 
             
            end
         | 
| 13 14 |  | 
| 14 | 
            -
            require  | 
| 15 | 
            -
            require  | 
| 15 | 
            +
            require 'todotxt/regex'
         | 
| 16 | 
            +
            require 'todotxt/version'
         | 
    
        data/lib/todotxt/cli.rb
    CHANGED
    
    | @@ -1,39 +1,41 @@ | |
| 1 | 
            -
            require  | 
| 2 | 
            -
            require  | 
| 3 | 
            -
            require  | 
| 4 | 
            -
            require  | 
| 1 | 
            +
            require 'thor'
         | 
| 2 | 
            +
            require 'rainbow'
         | 
| 3 | 
            +
            require 'chronic'
         | 
| 4 | 
            +
            require 'parseconfig'
         | 
| 5 5 |  | 
| 6 6 | 
             
            module Todotxt
         | 
| 7 | 
            +
              CFG_PATH = File.expand_path('~/.todotxt.cfg')
         | 
| 8 | 
            +
             | 
| 7 9 | 
             
              class CLI < Thor
         | 
| 8 10 | 
             
                include Thor::Actions
         | 
| 9 11 | 
             
                include Todotxt::CLIHelpers
         | 
| 10 12 |  | 
| 11 13 | 
             
                def self.source_root
         | 
| 12 | 
            -
                  File.join File.dirname(__FILE__),  | 
| 14 | 
            +
                  File.join File.dirname(__FILE__), '..', '..', 'conf'
         | 
| 13 15 | 
             
                end
         | 
| 14 16 |  | 
| 15 17 | 
             
                def initialize(*args)
         | 
| 16 18 | 
             
                  super
         | 
| 17 19 | 
             
                  # Allow testing colors, rainbow usually detects whether
         | 
| 18 | 
            -
                  #  the output goes to a TTY, but Aruba/Cucumber is not a | 
| 20 | 
            +
                  #  the output goes to a TTY, but Aruba/Cucumber is not a
         | 
| 19 21 | 
             
                  #  TTY, so we enforce it here, based on an environment var
         | 
| 20 | 
            -
                  Sickill::Rainbow.enabled = true if ENV[ | 
| 21 | 
            -
             | 
| 22 | 
            +
                  Sickill::Rainbow.enabled = true if ENV['FORCE_COLORS'] == 'TRUE'
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  # Open config file and render config.
         | 
| 25 | 
            +
                  @config = Config.new options
         | 
| 22 26 | 
             
                  @list   = nil
         | 
| 23 | 
            -
                  unless [ | 
| 27 | 
            +
                  unless %w[help generate_config generate_txt].include? ARGV[0]
         | 
| 24 28 | 
             
                    ask_and_create @config unless @config.file_exists?
         | 
| 25 | 
            -
                    if @config.deprecated?  | 
| 26 | 
            -
                      error_and_exit  | 
| 29 | 
            +
                    if @config.deprecated? && options[:file]
         | 
| 30 | 
            +
                      error_and_exit 'You are using an old config, which has no support for multiple files. Please update your configuration.'
         | 
| 27 31 | 
             
                    end
         | 
| 28 32 |  | 
| 29 | 
            -
                     | 
| 30 | 
            -
                     | 
| 31 | 
            -
                    @list = TodoList.new @file
         | 
| 33 | 
            +
                    ask_and_create @config.file unless @config.file.exists?
         | 
| 34 | 
            +
                    @list = TodoList.new @config.file
         | 
| 32 35 | 
             
                  end
         | 
| 33 | 
            -
             | 
| 34 36 | 
             
                end
         | 
| 35 37 |  | 
| 36 | 
            -
                class_option :file, : | 
| 38 | 
            +
                class_option :file, type: :string, desc: "Use a different file than todo.txt
         | 
| 37 39 | 
             
                 E.g. use 'done' to have the action performed on the file you set for 'done' in the todotxt
         | 
| 38 40 | 
             
                 configuration under [files]."
         | 
| 39 41 |  | 
| @@ -43,49 +45,57 @@ module Todotxt | |
| 43 45 | 
             
                # Listing
         | 
| 44 46 | 
             
                #
         | 
| 45 47 |  | 
| 46 | 
            -
                desc  | 
| 47 | 
            -
                method_option :done,   : | 
| 48 | 
            -
                method_option :simple, : | 
| 49 | 
            -
                 | 
| 50 | 
            -
             | 
| 51 | 
            -
                   | 
| 48 | 
            +
                desc 'list | ls [SEARCH]', 'List all todos, or todos matching SEARCH'
         | 
| 49 | 
            +
                method_option :done,   type: :boolean, aliases: '-d', desc: 'Include todo items that have been marked as done'
         | 
| 50 | 
            +
                method_option :simple, type: :boolean, desc: 'Simple output (for scripts, etc)'
         | 
| 51 | 
            +
                method_option :all,    type: :boolean, aliases: '-a', desc: 'List items from all files'
         | 
| 52 | 
            +
                def list(search = '')
         | 
| 53 | 
            +
                  if options[:all]
         | 
| 54 | 
            +
                    @config.files.each do |file|
         | 
| 55 | 
            +
                      count = @list.todos.count || 0
         | 
| 56 | 
            +
                      @list.todos += TodoList.new(file[1], count).todos unless file[0] == 'todo'
         | 
| 57 | 
            +
                    end
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  @list.filter(search, with_done: (options[:done] ? true : false))
         | 
| 61 | 
            +
                  render_list simple: !!options[:simple]
         | 
| 52 62 | 
             
                end
         | 
| 53 | 
            -
                map  | 
| 63 | 
            +
                map 'ls' => :list
         | 
| 54 64 |  | 
| 55 | 
            -
                desc  | 
| 56 | 
            -
                def lsdone  | 
| 57 | 
            -
                  @list.filter(search, : | 
| 65 | 
            +
                desc 'lsdone | lsd', 'List all done items'
         | 
| 66 | 
            +
                def lsdone(search = '')
         | 
| 67 | 
            +
                  @list.filter(search, only_done: true)
         | 
| 58 68 |  | 
| 59 69 | 
             
                  render_list
         | 
| 60 70 | 
             
                end
         | 
| 61 | 
            -
                map  | 
| 71 | 
            +
                map 'lsd' => :lsdone
         | 
| 62 72 |  | 
| 63 | 
            -
                desc  | 
| 73 | 
            +
                desc 'listproj | lsproj', 'List all projects'
         | 
| 64 74 | 
             
                def listproj
         | 
| 65 75 | 
             
                  @list.projects.each { |p| say p }
         | 
| 66 76 | 
             
                end
         | 
| 67 | 
            -
                map  | 
| 77 | 
            +
                map 'lsproj' => :listproj
         | 
| 68 78 |  | 
| 69 | 
            -
                desc  | 
| 79 | 
            +
                desc 'lscon | lsc', 'List all contexts'
         | 
| 70 80 | 
             
                def lscon
         | 
| 71 81 | 
             
                  @list.contexts.each { |c| say c }
         | 
| 72 82 | 
             
                end
         | 
| 73 | 
            -
                map  | 
| 83 | 
            +
                map 'lsc' => :lscon
         | 
| 74 84 |  | 
| 75 | 
            -
                desc  | 
| 85 | 
            +
                desc 'due', 'List due items'
         | 
| 76 86 | 
             
                def due
         | 
| 77 | 
            -
                  if ENV[ | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 81 | 
            -
             | 
| 87 | 
            +
                  today = if ENV['date'] # Allow testing to "freeze" the date
         | 
| 88 | 
            +
                            DateTime.parse(ENV['date']).to_date
         | 
| 89 | 
            +
                          else
         | 
| 90 | 
            +
                            DateTime.now.to_date
         | 
| 91 | 
            +
                          end
         | 
| 82 92 |  | 
| 83 | 
            -
                  puts "Due today (#{today.strftime( | 
| 93 | 
            +
                  puts "Due today (#{today.strftime('%Y-%m-%d')})".bright
         | 
| 84 94 | 
             
                  @list.on_date(today).each { |todo| puts format_todo(todo) }
         | 
| 85 95 | 
             
                  puts "\nPast-due items".bright
         | 
| 86 96 | 
             
                  @list.before_date(today).each { |todo| puts format_todo(todo) }
         | 
| 87 97 | 
             
                  puts "\nDue 7 days in advance".bright
         | 
| 88 | 
            -
                  ((today+1)..(today+7)).each do |day|
         | 
| 98 | 
            +
                  ((today + 1)..(today + 7)).each do |day|
         | 
| 89 99 | 
             
                    @list.on_date(day).each { |todo| puts format_todo(todo) }
         | 
| 90 100 | 
             
                  end
         | 
| 91 101 | 
             
                end
         | 
| @@ -94,7 +104,7 @@ module Todotxt | |
| 94 104 | 
             
                # Todo management
         | 
| 95 105 | 
             
                #
         | 
| 96 106 |  | 
| 97 | 
            -
                desc  | 
| 107 | 
            +
                desc 'add | a TEXT', 'Add a new Todo item'
         | 
| 98 108 | 
             
                def add(str, *str2)
         | 
| 99 109 | 
             
                  string = "#{str} #{str2.join(' ')}"
         | 
| 100 110 | 
             
                  todo = @list.add string
         | 
| @@ -103,10 +113,10 @@ module Todotxt | |
| 103 113 |  | 
| 104 114 | 
             
                  @list.save
         | 
| 105 115 | 
             
                end
         | 
| 106 | 
            -
                map  | 
| 116 | 
            +
                map 'a' => :add
         | 
| 107 117 |  | 
| 108 | 
            -
                desc  | 
| 109 | 
            -
                def do | 
| 118 | 
            +
                desc 'do ITEM#[, ITEM#, ITEM#, ...]', 'Mark ITEM# as done'
         | 
| 119 | 
            +
                def do(line1, *lines)
         | 
| 110 120 | 
             
                  lines.unshift(line1).each do |line|
         | 
| 111 121 | 
             
                    todo = @list.find_by_line line
         | 
| 112 122 | 
             
                    if todo
         | 
| @@ -120,8 +130,8 @@ module Todotxt | |
| 120 130 | 
             
                  end
         | 
| 121 131 | 
             
                end
         | 
| 122 132 |  | 
| 123 | 
            -
                desc  | 
| 124 | 
            -
                def undo | 
| 133 | 
            +
                desc 'undo | u ITEM#[, ITEM#, ITEM#, ...]', 'Mark ITEM# item as not done'
         | 
| 134 | 
            +
                def undo(line1, *lines)
         | 
| 125 135 | 
             
                  lines.unshift(line1).each do |line|
         | 
| 126 136 | 
             
                    todo = @list.find_by_line line
         | 
| 127 137 | 
             
                    if todo
         | 
| @@ -134,10 +144,10 @@ module Todotxt | |
| 134 144 | 
             
                    end
         | 
| 135 145 | 
             
                  end
         | 
| 136 146 | 
             
                end
         | 
| 137 | 
            -
                map  | 
| 147 | 
            +
                map 'u' => :undo
         | 
| 138 148 |  | 
| 139 | 
            -
                desc  | 
| 140 | 
            -
                def pri | 
| 149 | 
            +
                desc 'pri | p ITEM# PRIORITY', 'Set priority of ITEM# to PRIORITY'
         | 
| 150 | 
            +
                def pri(line, priority)
         | 
| 141 151 | 
             
                  todo = @list.find_by_line line
         | 
| 142 152 | 
             
                  if todo
         | 
| 143 153 | 
             
                    todo.prioritize priority
         | 
| @@ -148,10 +158,10 @@ module Todotxt | |
| 148 158 | 
             
                    error "No todo found at line #{line}"
         | 
| 149 159 | 
             
                  end
         | 
| 150 160 | 
             
                end
         | 
| 151 | 
            -
                map  | 
| 161 | 
            +
                map 'p' => :pri
         | 
| 152 162 |  | 
| 153 | 
            -
                desc  | 
| 154 | 
            -
                def dp | 
| 163 | 
            +
                desc 'dp | depri ITEM#[, ITEM#, ITEM#, ...]', 'Remove priority for ITEM#'
         | 
| 164 | 
            +
                def dp(line1, *lines)
         | 
| 155 165 | 
             
                  lines.unshift(line1).each do |line|
         | 
| 156 166 | 
             
                    todo = @list.find_by_line line
         | 
| 157 167 | 
             
                    if todo
         | 
| @@ -164,10 +174,10 @@ module Todotxt | |
| 164 174 | 
             
                    end
         | 
| 165 175 | 
             
                  end
         | 
| 166 176 | 
             
                end
         | 
| 167 | 
            -
                map  | 
| 177 | 
            +
                map 'depri' => :dp
         | 
| 168 178 |  | 
| 169 | 
            -
                desc  | 
| 170 | 
            -
                def append | 
| 179 | 
            +
                desc 'append | app ITEM# STRING', 'Append STRING to ITEM#'
         | 
| 180 | 
            +
                def append(line, str, *str2)
         | 
| 171 181 | 
             
                  string = "#{str} #{str2.join(' ')}"
         | 
| 172 182 | 
             
                  todo = @list.find_by_line line
         | 
| 173 183 | 
             
                  if todo
         | 
| @@ -179,10 +189,10 @@ module Todotxt | |
| 179 189 | 
             
                    error "No todo found at line #{line}"
         | 
| 180 190 | 
             
                  end
         | 
| 181 191 | 
             
                end
         | 
| 182 | 
            -
                map  | 
| 192 | 
            +
                map 'app' => :append
         | 
| 183 193 |  | 
| 184 | 
            -
                desc  | 
| 185 | 
            -
                def prepend | 
| 194 | 
            +
                desc 'prepend | prep ITEM# STRING', 'Prepend STRING to ITEM#'
         | 
| 195 | 
            +
                def prepend(line, str, *str2)
         | 
| 186 196 | 
             
                  string = "#{str} #{str2.join(' ')}"
         | 
| 187 197 | 
             
                  todo = @list.find_by_line line
         | 
| 188 198 | 
             
                  if todo
         | 
| @@ -194,10 +204,10 @@ module Todotxt | |
| 194 204 | 
             
                    error "No todo found at line #{line}"
         | 
| 195 205 | 
             
                  end
         | 
| 196 206 | 
             
                end
         | 
| 197 | 
            -
                map  | 
| 207 | 
            +
                map 'prep' => :prepend
         | 
| 198 208 |  | 
| 199 | 
            -
                desc  | 
| 200 | 
            -
                def replace | 
| 209 | 
            +
                desc 'replace ITEM# TEXT', 'Completely replace ITEM# text with TEXT'
         | 
| 210 | 
            +
                def replace(line, str, *str2)
         | 
| 201 211 | 
             
                  string = "#{str} #{str2.join(' ')}"
         | 
| 202 212 | 
             
                  todo = @list.find_by_line line
         | 
| 203 213 | 
             
                  if todo
         | 
| @@ -210,16 +220,16 @@ module Todotxt | |
| 210 220 | 
             
                  end
         | 
| 211 221 | 
             
                end
         | 
| 212 222 |  | 
| 213 | 
            -
                desc  | 
| 214 | 
            -
                method_option :force, : | 
| 215 | 
            -
                def del | 
| 223 | 
            +
                desc 'del | rm ITEM#[, ITEM#, ITEM#, ...]', 'Remove ITEM#'
         | 
| 224 | 
            +
                method_option :force, type: :boolean, aliases: '-f', desc: "Don't confirm removal"
         | 
| 225 | 
            +
                def del(line1, *lines)
         | 
| 216 226 | 
             
                  lines.unshift(line1).each do |line|
         | 
| 217 227 | 
             
                    todo = @list.find_by_line line
         | 
| 218 228 | 
             
                    if todo
         | 
| 219 229 | 
             
                      say format_todo(todo)
         | 
| 220 | 
            -
                      if options[:force] || yes?( | 
| 230 | 
            +
                      if options[:force] || yes?('Remove this item? [y/N]')
         | 
| 221 231 | 
             
                        @list.remove line
         | 
| 222 | 
            -
                        notice  | 
| 232 | 
            +
                        notice 'Removed from list'
         | 
| 223 233 |  | 
| 224 234 | 
             
                        @list.save
         | 
| 225 235 | 
             
                      end
         | 
| @@ -228,19 +238,19 @@ module Todotxt | |
| 228 238 | 
             
                    end
         | 
| 229 239 | 
             
                  end
         | 
| 230 240 | 
             
                end
         | 
| 231 | 
            -
                map  | 
| 241 | 
            +
                map 'rm' => :del
         | 
| 232 242 |  | 
| 233 | 
            -
                desc  | 
| 243 | 
            +
                desc 'edit', 'Open todo.txt file in your default editor'
         | 
| 234 244 | 
             
                def edit
         | 
| 235 | 
            -
                  system "#{@editor} #{@file.path}"
         | 
| 245 | 
            +
                  Kernel.system "#{@config.editor} #{@config.file.path}"
         | 
| 236 246 | 
             
                end
         | 
| 237 247 |  | 
| 238 | 
            -
                desc  | 
| 239 | 
            -
                def move | 
| 240 | 
            -
                  if @files[other_list_alias | 
| 248 | 
            +
                desc 'move | mv ITEM#[, ITEM#, ITEM#, ...] file', 'Move ITEM# to another file'
         | 
| 249 | 
            +
                def move(line1, *lines, other_list_alias)
         | 
| 250 | 
            +
                  if @config.files[other_list_alias].nil?
         | 
| 241 251 | 
             
                    error_and_exit "File alias #{other_list_alias} not found"
         | 
| 242 252 | 
             
                  else
         | 
| 243 | 
            -
                    other_list = TodoList.new @files[other_list_alias | 
| 253 | 
            +
                    other_list = TodoList.new @config.files[other_list_alias]
         | 
| 244 254 | 
             
                  end
         | 
| 245 255 |  | 
| 246 256 | 
             
                  lines.unshift(line1).each do |line|
         | 
| @@ -257,65 +267,42 @@ module Todotxt | |
| 257 267 | 
             
                    end
         | 
| 258 268 | 
             
                  end
         | 
| 259 269 | 
             
                end
         | 
| 260 | 
            -
                map  | 
| 261 | 
            -
             | 
| 262 | 
            -
                desc "move | mv ITEM#[, ITEM#, ITEM#, ...] file", "Move ITEM# to another file"
         | 
| 263 | 
            -
                def move line1, *lines, other_list_alias
         | 
| 264 | 
            -
                  if @files[other_list_alias.to_sym].nil?
         | 
| 265 | 
            -
                    error_and_exit "File alias #{other_list_alias} not found"
         | 
| 266 | 
            -
                  else
         | 
| 267 | 
            -
                    other_list = TodoList.new @files[other_list_alias.to_sym]
         | 
| 268 | 
            -
                  end
         | 
| 269 | 
            -
             | 
| 270 | 
            -
                  lines.unshift(line1).each do |line|
         | 
| 271 | 
            -
                    todo = @list.find_by_line line
         | 
| 272 | 
            -
                    if todo
         | 
| 273 | 
            -
                      say format_todo(todo)
         | 
| 274 | 
            -
                      @list.move line, other_list
         | 
| 275 | 
            -
                      notice "Moved to #{other_list}"
         | 
| 276 | 
            -
             | 
| 277 | 
            -
                      other_list.save
         | 
| 278 | 
            -
                      @list.save
         | 
| 279 | 
            -
                    else
         | 
| 280 | 
            -
                      error "No todo found at line #{line}"
         | 
| 281 | 
            -
                    end
         | 
| 282 | 
            -
                  end
         | 
| 283 | 
            -
                end
         | 
| 284 | 
            -
                map "mv" => :move
         | 
| 270 | 
            +
                map 'mv' => :move
         | 
| 285 271 |  | 
| 286 272 | 
             
                #
         | 
| 287 273 | 
             
                # File generation
         | 
| 288 274 | 
             
                #
         | 
| 289 275 |  | 
| 290 | 
            -
                desc  | 
| 276 | 
            +
                desc 'generate_config', 'Create a .todotxt.cfg file in your home folder, containing the path to todo.txt'
         | 
| 291 277 | 
             
                def generate_config
         | 
| 292 | 
            -
                  copy_file  | 
| 293 | 
            -
                  puts  | 
| 278 | 
            +
                  copy_file 'todotxt.cfg', Config.config_path
         | 
| 279 | 
            +
                  puts ''
         | 
| 294 280 | 
             
                end
         | 
| 295 281 |  | 
| 296 | 
            -
                desc  | 
| 282 | 
            +
                desc 'generate_txt', 'Create a sample todo.txt'
         | 
| 297 283 | 
             
                def generate_txt
         | 
| 298 | 
            -
                  copy_file  | 
| 299 | 
            -
                  puts  | 
| 284 | 
            +
                  copy_file 'todo.txt', @file
         | 
| 285 | 
            +
                  puts ''
         | 
| 300 286 | 
             
                end
         | 
| 301 287 |  | 
| 302 288 | 
             
                #
         | 
| 303 289 | 
             
                # Extras
         | 
| 304 290 | 
             
                #
         | 
| 305 291 |  | 
| 306 | 
            -
                desc  | 
| 292 | 
            +
                desc 'version', 'Show todotxt version'
         | 
| 307 293 | 
             
                def version
         | 
| 308 294 | 
             
                  say "todotxt #{VERSION}"
         | 
| 309 295 | 
             
                end
         | 
| 310 296 |  | 
| 311 | 
            -
             | 
| 312 | 
            -
             | 
| 297 | 
            +
                private
         | 
| 298 | 
            +
             | 
| 299 | 
            +
                def render_list(opts = {})
         | 
| 313 300 | 
             
                  numsize = @list.count + 1
         | 
| 314 301 | 
             
                  numsize = numsize.to_s.length + 0
         | 
| 315 302 |  | 
| 316 303 | 
             
                  @list.each do |t|
         | 
| 317 304 | 
             
                    if opts[:simple]
         | 
| 318 | 
            -
                      say "#{t.line} #{t | 
| 305 | 
            +
                      say "#{t.line} #{t}"
         | 
| 319 306 | 
             
                    else
         | 
| 320 307 | 
             
                      say format_todo(t, numsize)
         | 
| 321 308 | 
             
                    end
         | 
| @@ -327,49 +314,16 @@ module Todotxt | |
| 327 314 | 
             
                end
         | 
| 328 315 |  | 
| 329 316 | 
             
                # File should respond_to "basename", "path" and "generate!"
         | 
| 330 | 
            -
                def ask_and_create | 
| 317 | 
            +
                def ask_and_create(file)
         | 
| 331 318 | 
             
                  puts "#{file.basename} doesn't exist yet. Would you like to generate a sample file?"
         | 
| 332 319 | 
             
                  confirm_generate = yes? "Create #{file.path}? [y/N]"
         | 
| 333 320 |  | 
| 334 321 | 
             
                  if confirm_generate
         | 
| 335 322 | 
             
                    file.generate!
         | 
| 336 323 | 
             
                  else
         | 
| 337 | 
            -
                    puts  | 
| 324 | 
            +
                    puts ''
         | 
| 338 325 | 
             
                    exit
         | 
| 339 326 | 
             
                  end
         | 
| 340 327 | 
             
                end
         | 
| 341 | 
            -
             | 
| 342 | 
            -
                def parse_conf
         | 
| 343 | 
            -
                  @files = {}
         | 
| 344 | 
            -
             | 
| 345 | 
            -
                  return if @config.nil?
         | 
| 346 | 
            -
             | 
| 347 | 
            -
                  # Backwards compatibility with todo_txt_path
         | 
| 348 | 
            -
                  #   when old variable is still set, and no files=>todo 
         | 
| 349 | 
            -
                  #   given, fallback to this old version.
         | 
| 350 | 
            -
                  if @config["todo_txt_path"]
         | 
| 351 | 
            -
                    @files[:todo] ||= TodoFile.new(@config["todo_txt_path"])
         | 
| 352 | 
            -
                  else
         | 
| 353 | 
            -
                    # Fill the @files from settings.
         | 
| 354 | 
            -
                    @config["files"].each do |name, file_path|
         | 
| 355 | 
            -
                      unless file_path.empty?
         | 
| 356 | 
            -
                        @files[name.to_sym] = TodoFile.new(file_path)
         | 
| 357 | 
            -
                      end
         | 
| 358 | 
            -
                    end
         | 
| 359 | 
            -
                  end
         | 
| 360 | 
            -
             | 
| 361 | 
            -
                  # Determine what file should be activated, set that in @file
         | 
| 362 | 
            -
                  if options[:file]
         | 
| 363 | 
            -
                    file_sym = options[:file].to_sym
         | 
| 364 | 
            -
                    if @files.has_key? file_sym
         | 
| 365 | 
            -
                      @file = @files[file_sym]
         | 
| 366 | 
            -
                    end
         | 
| 367 | 
            -
                  else
         | 
| 368 | 
            -
                    @file = @files[:todo]
         | 
| 369 | 
            -
                  end
         | 
| 370 | 
            -
             | 
| 371 | 
            -
                  # Determine the editor
         | 
| 372 | 
            -
                  @editor = @config["editor"] || ENV["EDITOR"]
         | 
| 373 | 
            -
                end
         | 
| 374 328 | 
             
              end
         | 
| 375 329 | 
             
            end
         |