tlist 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in tlist.gemspec
4
+ gemspec
@@ -0,0 +1,20 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ tlist (0.0.1)
5
+ colorize
6
+ methodchain
7
+ trollop
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ colorize (0.5.8)
13
+ methodchain (0.4.2)
14
+ trollop (1.16.2)
15
+
16
+ PLATFORMS
17
+ ruby
18
+
19
+ DEPENDENCIES
20
+ tlist!
@@ -0,0 +1,17 @@
1
+ Copyright (c) 2011, Caleb Spare
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that
5
+ the following conditions are met:
6
+
7
+ Redistributions of source code must retain the above copyright notice, this list of conditions and the
8
+ following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of
9
+ conditions and the following disclaimer in the documentation and/or other materials provided with the
10
+ distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
11
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
12
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
13
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
14
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
15
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
16
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
17
+ DAMAGE.
@@ -0,0 +1,226 @@
1
+ tlist
2
+ =====
3
+
4
+ tlist is an extremely lightweight TODO list manager for your commandline. It was written to be the bare
5
+ minimum that would meet my particular needs. It takes its inspiration heavily from
6
+ [t](http://stevelosh.com/projects/t/), a wonderful tool in the same vein written by the amazing Steve Losh
7
+ (incidentally, owner of the prettiest website on the interwebs). tlist also borrows a workflow from
8
+ [Things](http://culturedcode.com/things/) (as described to me; I've never actually used it).
9
+
10
+ The are three primary features that separate tlist from t:
11
+
12
+ 1. tlist is optimized for the single-person use case. The order of the list can be significant (it can
13
+ represent a priority).
14
+ 2. tlist has a built-in notion of labels for each task.
15
+ 3. tlist can be used with a two-step workflow. Each new task is put into the "Unsorted" category, and then
16
+ later the unsorted tasks may all be sorted at once.
17
+
18
+ Point #3 is why tlist is very efficient in my workflow. When a new task occurs to me, I can add it to my queue
19
+ of new tasks with almost no overhead (this avoids interruping my current train of thought). Later, I can sort
20
+ through my new tasks and organize them all at once.
21
+
22
+ Installation
23
+ ------------
24
+
25
+ The easiest way to install tlist is to install the gem
26
+
27
+ gem install tlist
28
+
29
+ This will install all the dependencies for you. It requires Ruby (I've tested with 1.8.7 and 1.9.2).
30
+
31
+ You can also install the latest version from Github by cloning the
32
+ [repository](https://github.com/cespare/tlist) and then adding `tlist` to your path. You'll need to make sure
33
+ the following dependencies (gems) are installed:
34
+
35
+ * trollop
36
+ * colorize
37
+ * methodchain
38
+
39
+ After you've got tlist, you should set up a few things in your `.bashrc`/`.bash_profile`. First, specify your
40
+ chosen todo-list file as follows:
41
+
42
+ export TLIST_FILE=path/to/tlist_file.txt
43
+
44
+ (Pro-tip: put this in your Dropbox folder as a quick way to share your todo list between multiple computers.)
45
+ Next, you can get tab completion by sourcing the included file. Download `tlist_completion.bash` and put it
46
+ somewhere on your machine. Then
47
+
48
+ source path/to/tlist_completion.bash
49
+
50
+ (This is optional.) Finally, if you want to get really crazy, you might alias `tlist` to something shorter. I
51
+ do this as follows:
52
+
53
+ alias t=tlist
54
+ complete -F _tlist t
55
+
56
+ Now you should be ready to go. Make sure it works by checking that you see the following output at your
57
+ command line (be sure to source your `.bashrc` or open a new terminal first):
58
+
59
+ $ tlist
60
+ Unsorted
61
+ (No tasks)
62
+
63
+ Usage
64
+ -----
65
+
66
+ You can see the full list of options by typing
67
+
68
+ $ tlist --help
69
+
70
+ However, there are only a few that you'll typically need. I'll guide you through a typical workflow using
71
+ those commands.
72
+
73
+ Let's start by adding a few tasks.
74
+
75
+ $ tlist -a "Go to the bank"
76
+ Added task 'Go to the bank' to label 'Unsorted'.
77
+ $ tlist -a "Set up dentist appointment"
78
+ Added task 'Set up dentist appointment' to label 'Unsorted'.
79
+ $ tlist -a "Buy milk"
80
+ Added task 'Buy milk' to label 'Unsorted'.
81
+ $ tlist -a "Buy coffee"
82
+ Added task 'Buy coffee' to label 'Unsorted'.
83
+
84
+ (Note: tlist will join all arguments together, so you can type `$ tlist -a Go to the bank` with no quotes.
85
+ However, if you've got any `'` characters in the task it will be interpreted as the start of a single-quoted
86
+ string by bash, so it's good to get in the habit of quoting the whole task.) You can inspect your tasks by
87
+ simply using `tlist`:
88
+
89
+ $ tlist
90
+ Unsorted
91
+ * Go to the bank
92
+ * Set up dentist appointment
93
+ * Buy milk
94
+ * Buy coffee
95
+
96
+ Now, adding new tasks is extremely quick, but they go to this "Unsorted" label. Now let's suppose you have a
97
+ few spare minutes, so you decide to organize all your tasks.
98
+
99
+ $ tlist -s
100
+ Sorting 4 unsorted tasks.
101
+
102
+ Unsorted task:
103
+ > Go to the bank
104
+ No existing labels.
105
+ Other options:
106
+ n Create a new label
107
+ s Skip this task
108
+ q Abort
109
+ Select an option: n
110
+ Enter new label name: Errands
111
+ Added task 'Go to the bank' to new label 'Errands'.
112
+ Removed task 'Go to the bank' from label 'Unsorted'.
113
+
114
+ Unsorted task:
115
+ > Set up dentist appointment
116
+ ...
117
+
118
+ I'm ommitting extra output here, but you can see how this interactive sorting step lets you quickly sort the
119
+ tasks you made earlier. Let's suppose that your current task list looks like this:
120
+
121
+ $ tlist
122
+ Errands
123
+ 1. Go to the bank
124
+ 2. Set up dentist appointment
125
+
126
+ Groceries
127
+ 1. Buy milk
128
+ 2. Buy coffee
129
+
130
+ Unsorted
131
+ (No tasks)
132
+
133
+ We can easily remove tasks:
134
+
135
+ $ tlist -d
136
+ Errands
137
+ 1. Go to the bank
138
+ 2. Set up dentist appointment
139
+
140
+ Groceries
141
+ 3. Buy milk
142
+ 4. Buy coffee
143
+
144
+ Select a task to delete (1-4 or q to abort): 3
145
+ Removed task 'Buy milk' from label 'Groceries'.
146
+
147
+ It's also easy to restrict many of these operations to a specific label:
148
+
149
+ $ tlist -l Groceries -a Buy yogurt
150
+ Added task 'Buy yogurt' to label 'Groceries'.
151
+ $ tlist -l Groceries -a Buy fruit
152
+ Added task 'Buy fruit' to label 'Groceries'.
153
+ $ tlist -l Groceries
154
+ Groceries
155
+ 1. Buy coffee
156
+ 2. Buy yogurt
157
+ 3. Buy fruit
158
+
159
+ $ tlist -l Groceries -d
160
+ Groceries
161
+ 1. Buy coffee
162
+ 2. Buy yogurt
163
+ 3. Buy fruit
164
+
165
+ Select a task to delete (1-3 or q to abort): 2
166
+ Removed task 'Buy yogurt' from label 'Groceries'.
167
+
168
+ Advanced usage
169
+ --------------
170
+
171
+ In addition to these basic operations, there is a concept of a "working" label from which you are actively
172
+ completing items. You can get and set your working label as follows:
173
+
174
+ $ tlist -g
175
+ No working label set. Use $ tlist --current to set a working label.
176
+ $ tlist -c Errands
177
+ Set current working label to 'Errands'.
178
+ $ tlist -g
179
+ Errands
180
+
181
+ Once you've set a working label, you can quickly pop items from the list and delete them as you finish with
182
+ the `--next` and `--finish` commands:
183
+
184
+ $ tlist -n
185
+ Go to the bank
186
+ $ tlist -f
187
+ Removed task 'Go to the bank' from label 'Errands'.
188
+ $ tlist -n
189
+ Set up dentist appointment
190
+ $ tlist -f
191
+ Removed task 'Set up dentist appointment' from label 'Errands'.
192
+ Removed empty label 'Errands'.
193
+
194
+ One last command that is very useful is `--edit`. Just type
195
+
196
+ $ tlist -e
197
+
198
+ and the tlist file will be opened in your `$EDITOR`. Be careful not to change the formatting. The blank lines
199
+ are significant, as are the colons (signify labels) and `>` (signifies current label). It's often quickest to
200
+ do complex reorganization of your tasks in your editor, rather than the one-by-one operations that tlist
201
+ natively supports.
202
+
203
+ Tests
204
+ -----
205
+
206
+ The tests for tlist are in the `tests/` directory, and they're written using
207
+ [cram](https://bitheap.org/cram/). Install cram and then run all the tests with
208
+
209
+ $ cram test/*.t
210
+
211
+ Contributions
212
+ -------------
213
+
214
+ If you'd like to hack on tlist, go ahead and [fork the project on github](https://github.com/cespare/tlist).
215
+ Open a pull request if you'd like me to incorporate your changes, but keep in mind that I'd like to keep tlist
216
+ pretty lightweight so I may not accept large new features.
217
+
218
+ Author
219
+ ------
220
+
221
+ tlist was written by Caleb Spare (cespare on Github).
222
+
223
+ License
224
+ -------
225
+
226
+ [BSD 2-clause license](http://opensource.org/licenses/bsd-license.php); see LICENSE.txt.
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/TODO.md ADDED
@@ -0,0 +1,11 @@
1
+ TODO
2
+ ====
3
+
4
+ * Finish tests:
5
+ * sort
6
+ * current
7
+ * get-current
8
+ * next
9
+ * finish
10
+ * labels
11
+ * See if it's possible to fix bug with tab-completing labels with spaces.
@@ -0,0 +1,297 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require "trollop"
5
+ require "colorize"
6
+ require "methodchain"
7
+
8
+ UNSORTED_NAME = "Unsorted"
9
+
10
+ def print_numbered(item, number, total_items)
11
+ number_width = total_items.to_s.size + 1
12
+ puts "#{"#{number}.".ljust(number_width)} #{item}"
13
+ end
14
+
15
+ class Tlist
16
+ attr_reader :label_array, :label_hash
17
+ attr_accessor :current
18
+ def initialize(filename)
19
+ @filename = filename
20
+ # I'd like to have ordered hashes instead of keeping the list + the hash, but I want 1.8 compatibility.
21
+ @label_array = [] # Array of label names
22
+ @label_hash = {} # Label name => Array of tasks
23
+ @current = nil
24
+ end
25
+
26
+ def add_label(name)
27
+ raise "Invalid name '#{name}'" if name.start_with? "> "
28
+ @label_array << name
29
+ @label_hash[name] = []
30
+ end
31
+
32
+ def delete_label(name)
33
+ raise "No such label '#{name}'" unless @label_hash.include? name
34
+ @label_array.delete name
35
+ @label_hash.delete name
36
+ end
37
+
38
+ def resolve_label(label_part)
39
+ return UNSORTED_NAME unless label_part
40
+ selected_labels = @label_array.select { |l| l.downcase.index label_part.downcase }
41
+ if selected_labels.size > 1
42
+ raise "Error: '#{label}' matches multiple labels: #{selected_labels.join(', ')}."
43
+ end
44
+ selected_labels[0]
45
+ end
46
+
47
+ def set_current(label_part)
48
+ label = resolve_label label_part
49
+ raise "Error: no label matches '#{label_part}'." unless label
50
+ @current = label
51
+ puts "Set current working label to '#{label}'."
52
+ end
53
+
54
+ def add_task(label, task)
55
+ raise "Invalid task name." if task.strip.empty?
56
+ selected_label = resolve_label(label)
57
+ add_label(label) unless selected_label
58
+ label = selected_label || label
59
+ if @label_hash[label].include? task
60
+ raise "Error: '#{label}' already includes a task '#{task}'."
61
+ end
62
+ @label_hash[label] << task
63
+ puts "Added task '#{task}' to #{"new " unless selected_label}label '#{label}'."
64
+ end
65
+
66
+ def delete_task(label, task)
67
+ selected_label = resolve_label(label)
68
+ raise "Error: No such label '#{label}'." unless selected_label
69
+ unless @label_hash[selected_label].include? task
70
+ raise "Error: No such task '#{task}' in label '#{selected_label}'."
71
+ end
72
+ @label_hash[selected_label].delete task
73
+ puts "Removed task '#{task}' from label '#{selected_label}'."
74
+ if @label_hash[selected_label].empty? && selected_label != UNSORTED_NAME
75
+ delete_label selected_label
76
+ puts "Removed empty label '#{selected_label}'."
77
+ end
78
+ end
79
+
80
+ def next_task
81
+ raise "No working label is set." unless @current
82
+ tasks = @label_hash[@current]
83
+ raise "No tasks left in working label '#{@current}'." if tasks.empty?
84
+ tasks[0]
85
+ end
86
+
87
+ def print_all_tasks_numbered(label)
88
+ labels = (label ? [resolve_label(label)] : @label_array).reject { |label| @label_hash[label].empty? }
89
+ return {} if labels.empty?
90
+ result = {}
91
+ task_count = @label_hash.values_at(*labels).map(&:size).reduce(&:+)
92
+ number = 0
93
+ labels.each do |label|
94
+ print_label label
95
+ @label_hash[label].each do |task|
96
+ print_numbered task, number += 1, task_count
97
+ result[number] = [label, task]
98
+ end
99
+ puts
100
+ end
101
+ result
102
+ end
103
+
104
+ def print(label)
105
+ labels = label ? [resolve_label(label)] : @label_array
106
+ labels.each do |label|
107
+ print_label label
108
+ tasks = @label_hash[label]
109
+ if tasks.empty?
110
+ puts "(No tasks)"
111
+ elsif label == UNSORTED_NAME
112
+ tasks.each { |task| puts "* #{task}" }
113
+ else
114
+ tasks.each_with_index { |task, i| print_numbered task, i + 1, tasks.size }
115
+ end
116
+ puts
117
+ end
118
+ end
119
+
120
+ def print_label(name)
121
+ colored = name == UNSORTED_NAME ? name.blue.underline : name.green.underline
122
+ puts @current == name ? "#{colored} (Current)" : colored
123
+ end
124
+
125
+ def write_file!
126
+ File.open(@filename, "w") do |file|
127
+ @label_array.each do |label|
128
+ file.puts "#{"> " if @current == label}#{label}:"
129
+ @label_hash[label].each { |task| file.puts task }
130
+ file.puts
131
+ end
132
+ end
133
+ end
134
+
135
+ def self.from_file(filename)
136
+ raise "Bad file: #{filename}" unless File.file? filename
137
+ tlist = Tlist.new(filename)
138
+ lines = File.open(filename).readlines.map(&:strip)
139
+ expect_label = true
140
+ lines.each_with_index do |line, i|
141
+ if line.empty?
142
+ expect_label = true
143
+ next
144
+ end
145
+
146
+ if expect_label
147
+ current, label = line.match(/^(> )?(.*):$/).to_a[1..2]
148
+ raise "Error parsing #{filename} at line #{i + 1} (expecting label)." unless label
149
+ if tlist.label_hash.include? label
150
+ raise "Error parsing #{filename} at line #{i + 1} (duplicate label)."
151
+ end
152
+ if current
153
+ if tlist.current
154
+ raise "Error parsing #{filename} at line #{i + 1} (more than one label is marked as current)."
155
+ end
156
+ tlist.current = label
157
+ end
158
+ tlist.add_label label
159
+ expect_label = false
160
+ else
161
+ tlist.label_hash[tlist.label_array.last] << line
162
+ end
163
+ end
164
+
165
+ # Keep the unsorted task list at the end.
166
+ if tlist.label_hash.include? UNSORTED_NAME
167
+ tlist.label_array.delete UNSORTED_NAME
168
+ tlist.label_array << UNSORTED_NAME
169
+ else
170
+ tlist.add_label UNSORTED_NAME
171
+ end
172
+ tlist
173
+ end
174
+ end
175
+
176
+ MODES = [:print, :add, :sort, :delete, :edit, :next, :finish, :current, :get_current, :unsorted, :labels]
177
+
178
+ def get_mode(options)
179
+ modes = options.keys.select { |option| MODES.include?(option) && options[option] }
180
+ if modes.size > 1
181
+ puts "Error: only one of the following may be specified:"
182
+ MODES.each { |mode| puts " --#{mode}" }
183
+ exit 1
184
+ end
185
+ modes[0] || :print
186
+ end
187
+
188
+ todo_file = ENV["TLIST_FILE"]
189
+ abort "Need to set TLIST_FILE environment variable" unless todo_file
190
+ editor = ENV["EDITOR"] || "vim"
191
+
192
+ options = Trollop::options do
193
+ opt :print, "Print tasks (can omit this flag)."
194
+ opt :add, "Add a task"
195
+ opt :sort, "Sort unsorted tasks"
196
+ opt :delete, "Delete a task"
197
+ opt :label, "Limit to a particular label (used in combination with another option)",
198
+ :default => nil, :type => String
199
+ opt :edit, "Edit the task list file in your $EDITOR (use carefully)"
200
+ opt :current, "Set the current working label", :default => nil, :type => String
201
+ opt :get_current, "Get the current working label"
202
+ opt :next, "Print the next task in the current label"
203
+ opt :finish, "Delete the next task in the current label"
204
+ opt :unsorted, "Print unsorted tasks (shorthand for --print #{UNSORTED_NAME})"
205
+ opt :labels, "Print all labels"
206
+
207
+ # TODO: Decide whether to implement something like this
208
+ #opt :finish, "Move a task to the finished list", :default => false
209
+ #opt :print_finished, "Print finished tasks.", :default => false
210
+ end
211
+
212
+ begin
213
+ mode = get_mode(options)
214
+ exec "#{editor} #{todo_file}" if mode == :edit
215
+
216
+ tlist = Tlist.from_file(todo_file)
217
+ label = options[:label]
218
+ argument = ARGV.join(" ")
219
+
220
+ case mode
221
+ when :print
222
+ tlist.print label
223
+ when :unsorted
224
+ tlist.print UNSORTED_NAME
225
+ when :add
226
+ label = tlist.add_task(label, argument)
227
+ tlist.write_file!
228
+ when :sort
229
+ unsorted_tasks = tlist.label_hash[UNSORTED_NAME].clone
230
+ puts "Sorting #{unsorted_tasks.size} unsorted tasks."
231
+ unsorted_tasks.each do |task|
232
+ puts
233
+ labels = tlist.label_array - [UNSORTED_NAME]
234
+ puts "Unsorted task:"
235
+ puts "> #{task}".yellow
236
+ if labels.size >= 1
237
+ puts "Existing labels:"
238
+ labels.each_with_index { |label, i| print_numbered label, i + 1, labels.size }
239
+ else
240
+ puts "No existing labels."
241
+ end
242
+ puts "Other options:"
243
+ ["n Create a new label", "s Skip this task", "q Abort"].each { |option| puts option }
244
+ print "Select an option: "
245
+ choice = STDIN.gets.strip
246
+ case choice
247
+ when *(1..labels.size).map(&:to_s)
248
+ tlist.add_task labels[choice.to_i - 1], task
249
+ tlist.delete_task UNSORTED_NAME, task
250
+ tlist.write_file!
251
+ when "n", "new"
252
+ print "Enter new label name: "
253
+ tlist.add_task STDIN.gets.strip, task
254
+ tlist.delete_task UNSORTED_NAME, task
255
+ tlist.write_file!
256
+ when "s", "skip"
257
+ when "q", "quit", "a"
258
+ exit 0
259
+ else
260
+ raise "Error: '#{choice}' unrecognized option. Aborting."
261
+ end
262
+ end
263
+ when :delete
264
+ choices = tlist.print_all_tasks_numbered label
265
+ if choices.empty?
266
+ puts "No tasks."
267
+ else
268
+ range = choices.size == 1 ? "1" : "1-#{choices.size}"
269
+ print "Select a task to delete (#{range} or q to abort): "
270
+ choice = STDIN.gets.strip
271
+ case choice
272
+ when *choices.keys.map(&:to_s)
273
+ tlist.delete_task *choices[choice.to_i]
274
+ tlist.write_file!
275
+ when "q", "quit", "a"
276
+ exit 0
277
+ else
278
+ raise "Error: '#{choice}' unrecognized option. Aborting."
279
+ end
280
+ end
281
+ when :next
282
+ puts tlist.next_task
283
+ when :finish
284
+ task = tlist.next_task
285
+ tlist.delete_task tlist.current, task
286
+ tlist.write_file!
287
+ when :current
288
+ tlist.set_current options[:current]
289
+ tlist.write_file!
290
+ when :get_current
291
+ puts tlist.current.else { "No working label set. Use $ tlist --current to set a working label." }
292
+ when :labels
293
+ puts tlist.label_array.join(" ")
294
+ end
295
+ rescue RuntimeError => e
296
+ abort e.message
297
+ end
@@ -0,0 +1,50 @@
1
+ # Test adding new tasks
2
+
3
+ # Setup
4
+ $ touch tlist_file
5
+ $ export TLIST_FILE=tlist_file
6
+ $ PATH=$TESTDIR/../bin:$PATH
7
+
8
+ # Tests
9
+ $ tlist
10
+ Unsorted
11
+ (No tasks)
12
+
13
+ $ tlist -a task 1
14
+ Added task 'task 1' to label 'Unsorted'.
15
+ $ tlist
16
+ Unsorted
17
+ * task 1
18
+
19
+ $ tlist --label "Label1" --add task 2
20
+ Added task 'task 2' to new label 'Label1'.
21
+ $ tlist
22
+ Label1
23
+ 1. task 2
24
+
25
+ Unsorted
26
+ * task 1
27
+
28
+ $ tlist -l "Label1" -a task 3
29
+ Added task 'task 3' to label 'Label1'.
30
+ $ tlist
31
+ Label1
32
+ 1. task 2
33
+ 2. task 3
34
+
35
+ Unsorted
36
+ * task 1
37
+
38
+ $ tlist -l "Label2" -a task 4
39
+ Added task 'task 4' to new label 'Label2'.
40
+ $ tlist
41
+ Label1
42
+ 1. task 2
43
+ 2. task 3
44
+
45
+ Label2
46
+ 1. task 4
47
+
48
+ Unsorted
49
+ * task 1
50
+
@@ -0,0 +1,73 @@
1
+ # Deleting tasks.
2
+
3
+ # Setup
4
+ $ cp $TESTDIR/files/many_labels.txt tlist_file
5
+ $ export TLIST_FILE=tlist_file
6
+ $ PATH=$TESTDIR/../bin:$PATH
7
+
8
+ # Tests
9
+ # The long line below is confusing. There is no newline after ": " because '4' is echoed in. When the user
10
+ # inputs '4' from the prompt, a newline will separate the prompt from the response.
11
+ $ echo "4" | tlist --delete
12
+ Foo
13
+ 1. foo task 1
14
+ 2. foo task 2
15
+
16
+ Bar
17
+ 3. bar task 1
18
+
19
+ Baz
20
+ 4. baz task 1
21
+ 5. baz task 2
22
+ 6. baz task 3
23
+
24
+ Unsorted
25
+ 7. unsorted 1
26
+ 8. unsorted 2
27
+ 9. unsorted 3
28
+ 10. unsorted 4
29
+
30
+ Select a task to delete (1-10 or q to abort): Removed task 'baz task 1' from label 'Baz'.
31
+ $ tlist
32
+ Foo
33
+ 1. foo task 1
34
+ 2. foo task 2
35
+
36
+ Bar
37
+ 1. bar task 1
38
+
39
+ Baz
40
+ 1. baz task 2
41
+ 2. baz task 3
42
+
43
+ Unsorted
44
+ * unsorted 1
45
+ * unsorted 2
46
+ * unsorted 3
47
+ * unsorted 4
48
+
49
+ $ echo "3" | tlist -d -l unsor
50
+ Unsorted
51
+ 1. unsorted 1
52
+ 2. unsorted 2
53
+ 3. unsorted 3
54
+ 4. unsorted 4
55
+
56
+ Select a task to delete (1-4 or q to abort): Removed task 'unsorted 3' from label 'Unsorted'.
57
+ $ tlist
58
+ Foo
59
+ 1. foo task 1
60
+ 2. foo task 2
61
+
62
+ Bar
63
+ 1. bar task 1
64
+
65
+ Baz
66
+ 1. baz task 2
67
+ 2. baz task 3
68
+
69
+ Unsorted
70
+ * unsorted 1
71
+ * unsorted 2
72
+ * unsorted 4
73
+
File without changes
@@ -0,0 +1,7 @@
1
+ Foo:
2
+
3
+ Bar:
4
+
5
+ Baz:
6
+
7
+ Unsorted:
@@ -0,0 +1,17 @@
1
+ Foo:
2
+ foo task 1
3
+ foo task 2
4
+
5
+ Bar:
6
+ bar task 1
7
+
8
+ Baz:
9
+ baz task 1
10
+ baz task 2
11
+ baz task 3
12
+
13
+ Unsorted:
14
+ unsorted 1
15
+ unsorted 2
16
+ unsorted 3
17
+ unsorted 4
@@ -0,0 +1,7 @@
1
+ Foo:
2
+ foo task 1
3
+ foo task 2
4
+
5
+ Unsorted:
6
+ unsorted 1
7
+ unsorted 2
@@ -0,0 +1,4 @@
1
+ Foo:
2
+ foo task 1
3
+ foo task 2
4
+ foo task 3
@@ -0,0 +1,5 @@
1
+ Unsorted:
2
+ unsorted 1
3
+ unsorted 2
4
+ unsorted 3
5
+ unsorted 4
@@ -0,0 +1,86 @@
1
+ # Test printing various pre-made tlist files.
2
+
3
+ # Setup
4
+ $ PATH=$TESTDIR/../bin:$PATH
5
+
6
+ # Tests
7
+ $ TLIST_FILE=$TESTDIR/files/empty.txt tlist
8
+ Unsorted
9
+ (No tasks)
10
+
11
+ $ TLIST_FILE=$TESTDIR/files/empty.txt tlist --print
12
+ Unsorted
13
+ (No tasks)
14
+
15
+ $ TLIST_FILE=$TESTDIR/files/empty.txt tlist -p
16
+ Unsorted
17
+ (No tasks)
18
+
19
+ $ TLIST_FILE=$TESTDIR/files/empty_labels.txt tlist
20
+ Foo
21
+ (No tasks)
22
+
23
+ Bar
24
+ (No tasks)
25
+
26
+ Baz
27
+ (No tasks)
28
+
29
+ Unsorted
30
+ (No tasks)
31
+
32
+ $ TLIST_FILE=$TESTDIR/files/only_unsorted.txt tlist
33
+ Unsorted
34
+ * unsorted 1
35
+ * unsorted 2
36
+ * unsorted 3
37
+ * unsorted 4
38
+
39
+ $ TLIST_FILE=$TESTDIR/files/only_one_label.txt tlist
40
+ Foo
41
+ 1. foo task 1
42
+ 2. foo task 2
43
+ 3. foo task 3
44
+
45
+ Unsorted
46
+ (No tasks)
47
+
48
+ $ TLIST_FILE=$TESTDIR/files/one_label_and_unsorted.txt tlist
49
+ Foo
50
+ 1. foo task 1
51
+ 2. foo task 2
52
+
53
+ Unsorted
54
+ * unsorted 1
55
+ * unsorted 2
56
+
57
+ $ TLIST_FILE=$TESTDIR/files/many_labels.txt tlist
58
+ Foo
59
+ 1. foo task 1
60
+ 2. foo task 2
61
+
62
+ Bar
63
+ 1. bar task 1
64
+
65
+ Baz
66
+ 1. baz task 1
67
+ 2. baz task 2
68
+ 3. baz task 3
69
+
70
+ Unsorted
71
+ * unsorted 1
72
+ * unsorted 2
73
+ * unsorted 3
74
+ * unsorted 4
75
+
76
+ $ TLIST_FILE=$TESTDIR/files/many_labels.txt tlist --unsorted
77
+ Unsorted
78
+ * unsorted 1
79
+ * unsorted 2
80
+ * unsorted 3
81
+ * unsorted 4
82
+
83
+ $ TLIST_FILE=$TESTDIR/files/only_one_label.txt tlist -u
84
+ Unsorted
85
+ (No tasks)
86
+
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "tlist"
5
+ s.version = "0.0.1"
6
+ s.authors = ["Caleb Spare"]
7
+ s.email = ["cespare@gmail.com"]
8
+ s.homepage = ""
9
+ s.summary = "A simple todo-list"
10
+ s.description = "tlist is a small todo-list manager with labels for tasks and a highly efficient workflow."
11
+
12
+ s.rubyforge_project = "tlist"
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
16
+
17
+ s.add_dependency "trollop"
18
+ s.add_dependency "colorize"
19
+ s.add_dependency "methodchain"
20
+ end
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env bash
2
+
3
+ _tlist() {
4
+ local current_word
5
+ local options='--print --add --sort --delete --label --edit --current --get-current --next --finish
6
+ --unsorted --labels -p -a -s -d -l -e -c -g -n -f -u -b'
7
+ COMPREPLY=()
8
+ current_word=${COMP_WORDS[COMP_CWORD]}
9
+ if [[ ${#COMP_WORDS[@]} -gt 1 && $COMP_CWORD -gt 0 ]]; then
10
+ local previous_word=${COMP_WORDS[COMP_CWORD - 1]}
11
+ for test_label in "--label" "-l" "--current" "-c"; do
12
+ if [[ "$test_label" = "$previous_word" ]]; then
13
+ local labels=$(tlist --labels)
14
+ COMPREPLY=($(compgen -W "$labels" -- $current_word))
15
+ return 0
16
+ fi
17
+ done
18
+ fi
19
+ COMPREPLY=($(compgen -W "$options" -- $current_word))
20
+ return 0
21
+ }
22
+
23
+ complete -F _tlist tlist
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tlist
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Caleb Spare
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-09-06 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: trollop
16
+ requirement: &70256313193860 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70256313193860
25
+ - !ruby/object:Gem::Dependency
26
+ name: colorize
27
+ requirement: &70256313193420 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70256313193420
36
+ - !ruby/object:Gem::Dependency
37
+ name: methodchain
38
+ requirement: &70256313193000 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70256313193000
47
+ description: tlist is a small todo-list manager with labels for tasks and a highly
48
+ efficient workflow.
49
+ email:
50
+ - cespare@gmail.com
51
+ executables:
52
+ - tlist
53
+ extensions: []
54
+ extra_rdoc_files: []
55
+ files:
56
+ - .gitignore
57
+ - Gemfile
58
+ - Gemfile.lock
59
+ - LICENSE.txt
60
+ - README.md
61
+ - Rakefile
62
+ - TODO.md
63
+ - bin/tlist
64
+ - test/add.t
65
+ - test/delete.t
66
+ - test/files/empty.txt
67
+ - test/files/empty_labels.txt
68
+ - test/files/many_labels.txt
69
+ - test/files/one_label_and_unsorted.txt
70
+ - test/files/only_one_label.txt
71
+ - test/files/only_unsorted.txt
72
+ - test/print.t
73
+ - tlist.gemspec
74
+ - tlist_completion.bash
75
+ homepage: ''
76
+ licenses: []
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project: tlist
95
+ rubygems_version: 1.8.7
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: A simple todo-list
99
+ test_files: []