doing 0.2.4 → 0.2.5pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +67 -2
- data/bin/doing +94 -26
- data/lib/doing.rb +1 -0
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +191 -44
- metadata +18 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8806f026f8106baa4c033a2d30675e0f3c30afea
|
4
|
+
data.tar.gz: 77139cb8ae62cc18311d5fcd7c27a725806375c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6fb8b55cc46ceefe4c139af635417b2c318e90705ef7da3fb3aa2e2050bd7e7de89d4d9633e538ec0ca26e6d3582a81e3fa394ac3bf032684d463a36573f5cca
|
7
|
+
data.tar.gz: 659c26db54235f3ca7d13cc34bdc2f4cdd3e028cc6514c2c5f01c0c9216c7c0fcc693de629f3b965dd5b533e91b8390e09fdd29aebd010d5109ba947394ef16a
|
data/README.md
CHANGED
@@ -4,6 +4,8 @@
|
|
4
4
|
|
5
5
|
_If you're one of the rare people like me who find this useful, feel free to contribute to my [GitTip fund](https://www.gittip.com/ttscoff/) or just [buy me some coffee](http://brettterpstra.com/donate)._
|
6
6
|
|
7
|
+
[Changelog](#changelog)
|
8
|
+
|
7
9
|
## What and why
|
8
10
|
|
9
11
|
`doing` is a basic CLI for adding and listing "what was I doing" reminders in a [TaskPaper-formatted](http://www.hogbaysoftware.com/products/taskpaper) text file. It allows for multiple sections/categories and flexible output formatting.
|
@@ -313,17 +315,63 @@ Display any of the custom views you make in `~/.doingrc` with the `view` command
|
|
313
315
|
|
314
316
|
#### Utilities
|
315
317
|
|
316
|
-
archive - Move
|
318
|
+
archive - Move entries between sections
|
317
319
|
open - Open the "doing" file in an editor (OS X)
|
318
320
|
config - Edit the default configuration
|
319
321
|
|
322
|
+
#### Archiving
|
323
|
+
|
324
|
+
COMMAND OPTIONS
|
325
|
+
-k, --keep=arg - Count to keep (ignored if archiving by tag) (default: 5)
|
326
|
+
-t, --to=arg - Move entries to (default: Archive)
|
327
|
+
-b, --bool=arg - Tag boolean (default: AND)
|
328
|
+
|
329
|
+
The `archive` command will move entries from one section (default: Currently) to another section (default: Archive).
|
330
|
+
|
331
|
+
`doing archive` on its own will move all but the most recent 5 entries from currently into the archive.
|
332
|
+
|
333
|
+
`doing archive other_section` will archive from "other_section" to Archive.
|
334
|
+
|
335
|
+
`doing archive other_section -t alternate` will move from "other_section" to "alternate." You can use the `-k` flag on any of these to change the number of items to leave behind. To move everything, use `-k 0`.
|
336
|
+
|
337
|
+
You can also use tags to archive. You define the section first, and anything following it is treated as tags. If your first argument starts with "@", it will assume all sections and assume any following arguments are tags.
|
338
|
+
|
339
|
+
By default tag archiving uses an "AND" boolean, meaning all the tags listed must exist on the entry for it to be moved. You can change this behavior with `-b OR` or `-b NONE` ("ALL" and "ANY" also work).
|
340
|
+
|
341
|
+
Example: Archive all Currently items for @client that are marked @done
|
342
|
+
|
343
|
+
doing archive @client @done
|
344
|
+
|
320
345
|
---
|
321
346
|
|
322
347
|
## Extras
|
323
348
|
|
324
349
|
### Bash completion
|
325
350
|
|
326
|
-
|
351
|
+
See the file `doing.completion.bash` in the git repository for full bash completion. Thanks to [fcrespo82](https://github.com/fcrespo82) for getting it [started](https://gist.github.com/fcrespo82/9609318).
|
352
|
+
|
353
|
+
### Launchbar
|
354
|
+
|
355
|
+
The previous incarnation of `doing` had a [LaunchBar](http://obdev.at/launchbar/) action that I used frequently. The Day One popup has mostly replaced that for me, but only because I have a system that connects it to my WWID file. However, I've still found a place for adding WWID entries without including them in my journal, and LaunchBar is the perfect way to do that for me.
|
356
|
+
|
357
|
+
All you need is an AppleScript saved at "~/Library/Application Support/LaunchBar/Actions/Doing.scpt". It should look like this:
|
358
|
+
|
359
|
+
|
360
|
+
on handle_string(message)
|
361
|
+
-- get the input from LaunchBar
|
362
|
+
if message is "?" then
|
363
|
+
-- if the input is just "?" display the last three entries
|
364
|
+
set _doing to do shell script "/usr/bin/doing recent 3"
|
365
|
+
tell application "LaunchBar" to display in large type _doing
|
366
|
+
else
|
367
|
+
-- otherwise, create a new entry using the input
|
368
|
+
do shell script "/usr/bin/doing now " & quoted form of message
|
369
|
+
end if
|
370
|
+
|
371
|
+
end handle_string
|
372
|
+
|
373
|
+
|
374
|
+
Evan Lovely has [converted this to an Alfred workflow as well](http://www.evanlovely.com/blog/technology/alfred-for-terpstras-doing/).
|
327
375
|
|
328
376
|
## Troubleshooting
|
329
377
|
|
@@ -358,3 +406,20 @@ I'm not making any money on `doing`, and I don't plan to spend a lot of time fix
|
|
358
406
|
That said, you can get support from other users (and occasionally me) on GitHub. If you run into a replicatable issue in your environment, please [post an issue](https://github.com/ttscoff/doing/issues) and include your platform, OS version, and the result of `ruby -v`, along with a copy/paste of the error message.
|
359
407
|
|
360
408
|
Please try not to email me directly about GitHub projects.
|
409
|
+
|
410
|
+
### Changelog
|
411
|
+
|
412
|
+
#### 0.2.5 / 2014-03-21
|
413
|
+
|
414
|
+
* Default to showing times #26, show totals even if no tags exist #27, fix indentation #29
|
415
|
+
* Add section label to archived tasks automatically, excepting Currently section
|
416
|
+
* Today outputs and backdate for finish
|
417
|
+
* html styling and fix for 1.8.7 haml errors
|
418
|
+
* Look, HTML output! (`--output html`)
|
419
|
+
* Also, `--output csv`
|
420
|
+
* let doing archive function on all sections
|
421
|
+
* option to exclude date from `@done`,
|
422
|
+
* output newlines in sections and views
|
423
|
+
* Flagging (`doing mark`)
|
424
|
+
* fix for view/section guess error
|
425
|
+
* Adding tag filtering to archive command (`doing archive @done`)
|
data/bin/doing
CHANGED
@@ -47,6 +47,7 @@ command :now do |c|
|
|
47
47
|
c.action do |global_options,options,args|
|
48
48
|
if options[:back]
|
49
49
|
date = wwid.chronify(options[:back])
|
50
|
+
|
50
51
|
raise "Unable to parse date string" if date.nil?
|
51
52
|
else
|
52
53
|
date = Time.now
|
@@ -135,6 +136,10 @@ end
|
|
135
136
|
desc 'Add a completed item with @done(date). No argument finishes last entry.'
|
136
137
|
arg_name 'entry'
|
137
138
|
command :done do |c|
|
139
|
+
c.desc 'Include date'
|
140
|
+
c.default_value true
|
141
|
+
c.switch [:d,:date], :default_value => true
|
142
|
+
|
138
143
|
c.desc 'Immediately archive the entry'
|
139
144
|
c.default_value false
|
140
145
|
c.switch [:a,:archive], :negatable => false, :default_value => false
|
@@ -163,6 +168,7 @@ command :done do |c|
|
|
163
168
|
end
|
164
169
|
|
165
170
|
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
171
|
+
donedate = options[:d] ? "(#{Time.now.strftime('%F %R')})" : ""
|
166
172
|
|
167
173
|
if options[:e]
|
168
174
|
raise "No EDITOR variable defined in environment" if ENV['EDITOR'].nil?
|
@@ -171,7 +177,7 @@ command :done do |c|
|
|
171
177
|
input = wwid.fork_editor(input)
|
172
178
|
if input
|
173
179
|
title, note = wwid.format_input(input)
|
174
|
-
title += " @done
|
180
|
+
title += " @done#{donedate}"
|
175
181
|
section = "Archive" if options[:a]
|
176
182
|
wwid.add_item(title.cap_first, section.cap_first, {:note => note, :back => date})
|
177
183
|
wwid.write(wwid.doing_file)
|
@@ -179,17 +185,17 @@ command :done do |c|
|
|
179
185
|
raise "No content"
|
180
186
|
end
|
181
187
|
elsif args.length == 0 && STDIN.stat.size == 0
|
182
|
-
wwid.tag_last({:tags => ["done"], :count => 1, :section => section, :archive => options[:a], :back => date})
|
188
|
+
wwid.tag_last({:tags => ["done"], :count => 1, :section => section, :archive => options[:a], :back => date, :date => options[:d]})
|
183
189
|
else
|
184
190
|
if args.length > 0
|
185
191
|
title, note = wwid.format_input(args.join(" "))
|
186
|
-
title += " @done
|
192
|
+
title += " @done#{donedate}"
|
187
193
|
section = "Archive" if options[:a]
|
188
194
|
wwid.add_item(title.cap_first, section.cap_first, {:note => note, :back => date})
|
189
195
|
wwid.write(wwid.doing_file)
|
190
196
|
elsif STDIN.stat.size > 0
|
191
197
|
title, note = wwid.format_input(STDIN.read)
|
192
|
-
title += " @done
|
198
|
+
title += " @done#{donedate}"
|
193
199
|
section = options[:a] ? "Archive" : section
|
194
200
|
wwid.add_item(title.cap_first, section.cap_first, {:note => note, :back => date})
|
195
201
|
wwid.write(wwid.doing_file)
|
@@ -203,6 +209,13 @@ end
|
|
203
209
|
desc 'Mark last X entries as @done'
|
204
210
|
arg_name 'count'
|
205
211
|
command :finish do |c|
|
212
|
+
c.desc 'Include date'
|
213
|
+
c.default_value true
|
214
|
+
c.switch [:d,:date], :default_value => true
|
215
|
+
|
216
|
+
c.desc 'Backdate to "date_string" (natural language)'
|
217
|
+
c.flag [:back]
|
218
|
+
|
206
219
|
c.desc 'Archive entries'
|
207
220
|
c.default_value false
|
208
221
|
c.switch [:a,:archive], :negatable => false, :default_value => false
|
@@ -215,11 +228,19 @@ command :finish do |c|
|
|
215
228
|
|
216
229
|
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
217
230
|
|
231
|
+
if options[:back]
|
232
|
+
date = wwid.chronify(options[:back])
|
233
|
+
|
234
|
+
raise "Unable to parse date string" if date.nil?
|
235
|
+
else
|
236
|
+
date = Time.now
|
237
|
+
end
|
238
|
+
|
218
239
|
if args.length > 1
|
219
240
|
raise "Only one argument allowed"
|
220
241
|
elsif args.length == 0 || args[0] =~ /\d+/
|
221
242
|
count = args[0] ? args[0].to_i : 1
|
222
|
-
wwid.tag_last({:tags => ["done"], :count => count, :section => section, :archive => options[:a]})
|
243
|
+
wwid.tag_last({:tags => ["done"], :count => count, :section => section, :archive => options[:a], :date => options[:d], :back => date })
|
223
244
|
else
|
224
245
|
raise "Invalid argument (specify number of recent items to mark @done)"
|
225
246
|
end
|
@@ -266,6 +287,24 @@ command :tag do |c|
|
|
266
287
|
end
|
267
288
|
end
|
268
289
|
|
290
|
+
desc 'Mark last entry as highlighted'
|
291
|
+
command :mark do |c|
|
292
|
+
c.desc 'Section'
|
293
|
+
c.default_value wwid.current_section
|
294
|
+
c.flag [:s,:section], :default_value => wwid.current_section
|
295
|
+
|
296
|
+
c.desc 'Remove mark'
|
297
|
+
c.default_value false
|
298
|
+
c.switch [:r,:remove], :negatable => false, :default_value => false
|
299
|
+
|
300
|
+
|
301
|
+
c.action do |global_options,options,args|
|
302
|
+
mark = wwid.config['marker_tag'] || "flagged"
|
303
|
+
wwid.tag_last({:tags => [mark], :section => options[:s], :remove => options[:r]})
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
|
269
308
|
|
270
309
|
desc 'List all entries'
|
271
310
|
arg_name 'section [tags]'
|
@@ -286,13 +325,12 @@ command :show do |c|
|
|
286
325
|
c.default_value 'asc'
|
287
326
|
c.flag [:s,:sort], :default_value => 'asc'
|
288
327
|
|
289
|
-
c.desc 'Output to
|
290
|
-
c.
|
291
|
-
c.switch [:csv], :default_value => false, :negatable => false
|
328
|
+
c.desc 'Output to format'
|
329
|
+
c.flag [:o,:output]
|
292
330
|
|
293
331
|
c.desc 'Show time intervals on @done tasks'
|
294
332
|
c.default_value false
|
295
|
-
c.switch [:t,:times], :default_value =>
|
333
|
+
c.switch [:t,:times], :default_value => true
|
296
334
|
|
297
335
|
c.desc 'Show intervals with totals at the end of output'
|
298
336
|
c.default_value false
|
@@ -327,7 +365,7 @@ command :show do |c|
|
|
327
365
|
|
328
366
|
options[:t] = true if options[:totals]
|
329
367
|
|
330
|
-
puts wwid.list_section({:section => section, :count => options[:c].to_i, :tag_filter => tag_filter, :age => options[:a], :order => options[:s], :
|
368
|
+
puts wwid.list_section({:section => section, :count => options[:c].to_i, :tag_filter => tag_filter, :age => options[:a], :order => options[:s], :output => options[:output], :times => options[:t], :highlight => true})
|
331
369
|
|
332
370
|
puts wwid.tag_times if options[:totals]
|
333
371
|
|
@@ -341,6 +379,15 @@ command :recent do |c|
|
|
341
379
|
c.desc 'Section'
|
342
380
|
c.default_value wwid.current_section
|
343
381
|
c.flag [:s,:section], :default_value => wwid.current_section
|
382
|
+
|
383
|
+
c.desc 'Show time intervals on @done tasks'
|
384
|
+
c.default_value false
|
385
|
+
c.switch [:t,:times], :default_value => true
|
386
|
+
|
387
|
+
c.desc 'Show intervals with totals at the end of output'
|
388
|
+
c.default_value false
|
389
|
+
c.switch [:totals], :default_value => false, :negatable => true
|
390
|
+
|
344
391
|
c.action do |global_options,options,args|
|
345
392
|
|
346
393
|
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
@@ -351,7 +398,11 @@ command :recent do |c|
|
|
351
398
|
else
|
352
399
|
count = 10
|
353
400
|
end
|
354
|
-
|
401
|
+
options[:t] = true if options[:totals]
|
402
|
+
|
403
|
+
puts wwid.recent(count,section.cap_first,{ :times => options[:t] })
|
404
|
+
|
405
|
+
puts wwid.tag_times if options[:totals]
|
355
406
|
end
|
356
407
|
end
|
357
408
|
end
|
@@ -360,17 +411,20 @@ desc 'List entries from today'
|
|
360
411
|
command :today do |c|
|
361
412
|
c.desc 'Show time intervals on @done tasks'
|
362
413
|
c.default_value false
|
363
|
-
c.switch [:t,:times], :default_value =>
|
414
|
+
c.switch [:t,:times], :default_value => true
|
364
415
|
|
365
416
|
c.desc 'Show time totals at the end of output'
|
366
417
|
c.default_value false
|
367
418
|
c.switch [:totals], :default_value => false, :negatable => true
|
368
419
|
|
420
|
+
c.desc 'Output to format'
|
421
|
+
c.flag [:o,:output]
|
422
|
+
|
369
423
|
c.action do |global_options,options,args|
|
370
424
|
|
371
425
|
options[:t] = true if options[:totals]
|
372
426
|
|
373
|
-
puts wwid.today(options[:t]).
|
427
|
+
puts wwid.today(options[:t],options[:output]).chomp
|
374
428
|
|
375
429
|
puts wwid.tag_times if options[:totals]
|
376
430
|
end
|
@@ -386,7 +440,7 @@ end
|
|
386
440
|
desc 'List sections'
|
387
441
|
command :sections do |c|
|
388
442
|
c.action do |global_options,options,args|
|
389
|
-
puts wwid.sections.join("
|
443
|
+
puts wwid.sections.join("\t")
|
390
444
|
end
|
391
445
|
end
|
392
446
|
|
@@ -420,13 +474,12 @@ command :view do |c|
|
|
420
474
|
c.desc 'Count to display (override view settings)'
|
421
475
|
c.flag [:c,:count], :must_match => /^\d+$/, :type => Integer
|
422
476
|
|
423
|
-
c.desc 'Output to
|
424
|
-
c.
|
425
|
-
c.switch [:csv], :default_value => false, :negatable => false
|
477
|
+
c.desc 'Output to format'
|
478
|
+
c.flag [:o,:output]
|
426
479
|
|
427
480
|
c.desc 'Show time intervals on @done tasks'
|
428
481
|
c.default_value false
|
429
|
-
c.switch [:t,:times], :default_value =>
|
482
|
+
c.switch [:t,:times], :default_value => true
|
430
483
|
|
431
484
|
c.desc 'Show intervals with totals at the end of output'
|
432
485
|
c.default_value false
|
@@ -455,7 +508,7 @@ command :view do |c|
|
|
455
508
|
if view['tags'].class == Array
|
456
509
|
tag_filter['tags'] = view['tags'].map{|tag| tag.strip }
|
457
510
|
else
|
458
|
-
tag_filter['tags'] = view['tags'].split(" ").map{|tag| tag.strip }
|
511
|
+
tag_filter['tags'] = view['tags'].gsub(/[, ]+/," ").split(" ").map{|tag| tag.strip }
|
459
512
|
end
|
460
513
|
tag_filter['bool'] = view.has_key?('tags_bool') && !view['tags_bool'].nil? ? view['tags_bool'].upcase : "OR"
|
461
514
|
end
|
@@ -464,8 +517,8 @@ command :view do |c|
|
|
464
517
|
section = options[:s] ? section : view.has_key?('section') ? view['section'] : wwid.current_section
|
465
518
|
order = view.has_key?('order') ? view['order'] : "asc"
|
466
519
|
options[:t] = true if options[:totals]
|
467
|
-
|
468
|
-
puts wwid.list_section({:section => section, :count => count, :template => template, :format => format, :order => order, :tag_filter => tag_filter, :
|
520
|
+
options[:output].downcase! if options[:output]
|
521
|
+
puts wwid.list_section({:section => section, :count => count, :template => template, :format => format, :order => order, :tag_filter => tag_filter, :output => options[:output], :tags_color => tags_color, :times => options[:t], :highlight => true })
|
469
522
|
|
470
523
|
puts wwid.tag_times if options[:totals]
|
471
524
|
else
|
@@ -477,25 +530,40 @@ end
|
|
477
530
|
desc 'List available custom views'
|
478
531
|
command :views do |c|
|
479
532
|
c.action do |global_options,options,args|
|
480
|
-
puts wwid.views.join("
|
533
|
+
puts wwid.views.join("\t")
|
481
534
|
end
|
482
535
|
end
|
483
536
|
|
484
|
-
desc 'Move
|
537
|
+
desc 'Move entries in between sections'
|
485
538
|
arg_name 'section'
|
486
539
|
default_value wwid.current_section
|
487
540
|
command :archive do |c|
|
488
|
-
c.desc 'Count to keep'
|
541
|
+
c.desc 'Count to keep (ignored if archiving by tag)'
|
489
542
|
c.default_value 5
|
490
543
|
c.flag [:k,:keep], :default_value => 5, :must_match => /^\d+$/, :type => Integer
|
491
544
|
|
545
|
+
c.desc 'Move entries to'
|
546
|
+
c.default_value "Archive"
|
547
|
+
c.flag [:t,:to], :default_value => "Archive"
|
548
|
+
|
549
|
+
c.desc 'Tag boolean'
|
550
|
+
c.default_value "AND"
|
551
|
+
c.flag [:b,:bool], :default_value => "AND"
|
552
|
+
|
492
553
|
c.action do |global_options,options,args|
|
493
554
|
if args.length > 0
|
494
|
-
|
555
|
+
if args[0] =~ /^@\S+/
|
556
|
+
section = "all"
|
557
|
+
tags = args.map {|t| t.sub(/^@/,'').strip }
|
558
|
+
else
|
559
|
+
section = args[0].cap_first
|
560
|
+
tags = args.length > 1 ? args[1..-1].map {|t| t.sub(/^@/,'').strip } : nil
|
561
|
+
end
|
495
562
|
else
|
496
563
|
section = wwid.current_section
|
564
|
+
tags = nil
|
497
565
|
end
|
498
|
-
wwid.archive(section,options[:k])
|
566
|
+
wwid.archive(section,options[:k],options[:t],tags,options[:b])
|
499
567
|
end
|
500
568
|
end
|
501
569
|
|
data/lib/doing.rb
CHANGED
data/lib/doing/version.rb
CHANGED
data/lib/doing/wwid.rb
CHANGED
@@ -5,6 +5,7 @@ class String
|
|
5
5
|
m.upcase
|
6
6
|
end
|
7
7
|
end
|
8
|
+
|
8
9
|
end
|
9
10
|
|
10
11
|
class WWID
|
@@ -60,6 +61,8 @@ class WWID
|
|
60
61
|
'order' => "asc"
|
61
62
|
}
|
62
63
|
}
|
64
|
+
@config['marker_tag'] ||= 'flagged'
|
65
|
+
@config['marker_color'] ||= 'red'
|
63
66
|
|
64
67
|
@doing_file = File.expand_path(config['doing_file'])
|
65
68
|
@current_section = config['current_section']
|
@@ -213,8 +216,9 @@ class WWID
|
|
213
216
|
@content[title.cap_first] = {'original' => "#{title}:", 'items' => []}
|
214
217
|
end
|
215
218
|
|
216
|
-
def guess_section(frag)
|
217
|
-
|
219
|
+
def guess_section(frag,guessed=false)
|
220
|
+
return "All" if frag =~ /all/i
|
221
|
+
sections.each {|section| return section.cap_first if frag.downcase == section.downcase }
|
218
222
|
section = false
|
219
223
|
re = frag.split('').join(".*?")
|
220
224
|
sections.each {|sect|
|
@@ -224,18 +228,25 @@ class WWID
|
|
224
228
|
break
|
225
229
|
end
|
226
230
|
}
|
227
|
-
unless section
|
228
|
-
alt = guess_view(frag)
|
231
|
+
unless section || guessed
|
232
|
+
alt = guess_view(frag,true)
|
229
233
|
if alt
|
230
234
|
raise "Did you mean `doing view #{alt}`?"
|
231
235
|
else
|
232
|
-
|
236
|
+
print "Create a new section called #{frag.cap_first} (y/N)?"
|
237
|
+
input = STDIN.gets
|
238
|
+
if input =~ /^y/i
|
239
|
+
add_section(frag.cap_first)
|
240
|
+
write(doing_file)
|
241
|
+
return frag.cap_first
|
242
|
+
end
|
243
|
+
raise "Unknown section: #{frag}"
|
233
244
|
end
|
234
245
|
end
|
235
|
-
section.cap_first
|
246
|
+
section ? section.cap_first : section
|
236
247
|
end
|
237
248
|
|
238
|
-
def guess_view(frag)
|
249
|
+
def guess_view(frag,guessed=false)
|
239
250
|
views.each {|view| return view if frag.downcase == view.downcase}
|
240
251
|
view = false
|
241
252
|
re = frag.split('').join(".*?")
|
@@ -246,12 +257,12 @@ class WWID
|
|
246
257
|
break
|
247
258
|
end
|
248
259
|
}
|
249
|
-
unless view
|
250
|
-
alt = guess_section(frag)
|
260
|
+
unless view || guessed
|
261
|
+
alt = guess_section(frag,true)
|
251
262
|
if alt
|
252
263
|
raise "Did you mean `doing show #{alt}`?"
|
253
264
|
else
|
254
|
-
raise "
|
265
|
+
raise "Unknown view: #{frag}"
|
255
266
|
end
|
256
267
|
end
|
257
268
|
view
|
@@ -278,6 +289,7 @@ class WWID
|
|
278
289
|
opt[:tags] ||= ["done"]
|
279
290
|
opt[:date] ||= false
|
280
291
|
opt[:remove] ||= false
|
292
|
+
opt[:back] ||= Time.now
|
281
293
|
|
282
294
|
opt[:section] = guess_section(opt[:section])
|
283
295
|
|
@@ -290,11 +302,11 @@ class WWID
|
|
290
302
|
title = item['title']
|
291
303
|
opt[:tags].each {|tag|
|
292
304
|
if opt[:remove]
|
293
|
-
title.gsub!(/ @#{tag}/,'')
|
305
|
+
title.gsub!(/(^| )@#{tag}/,'')
|
294
306
|
else
|
295
307
|
unless title =~ /@#{tag}/
|
296
|
-
if tag == "done" || opt[:date]
|
297
|
-
title += " @#{tag}(#{
|
308
|
+
if (tag == "done" && opt[:date]) || opt[:date]
|
309
|
+
title += " @#{tag}(#{opt[:back].strftime('%F %R')})"
|
298
310
|
else
|
299
311
|
title += " @#{tag}"
|
300
312
|
end
|
@@ -305,9 +317,9 @@ class WWID
|
|
305
317
|
}
|
306
318
|
|
307
319
|
if opt[:archive] && opt[:section] != "Archive"
|
308
|
-
archived = @content[opt[:section]]['items'][0..opt[:count]-1]
|
320
|
+
archived = @content[opt[:section]]['items'][0..opt[:count]-1].concat(@content['Archive']['items'])
|
309
321
|
@content[opt[:section]]['items'] = @content[opt[:section]]['items'][opt[:count]..-1]
|
310
|
-
@content['Archive']['items'] = archived
|
322
|
+
@content['Archive']['items'] = archived
|
311
323
|
end
|
312
324
|
|
313
325
|
write(@doing_file)
|
@@ -324,7 +336,7 @@ class WWID
|
|
324
336
|
end
|
325
337
|
@content.each {|title, section|
|
326
338
|
output += section['original'] + "\n"
|
327
|
-
output += list_section({:section => title, :template => "\t- %date | %title%note"})
|
339
|
+
output += list_section({:section => title, :template => "\t- %date | %title%note", :highlight => false})
|
328
340
|
}
|
329
341
|
output += @other_content_bottom.join("\n")
|
330
342
|
if file.nil?
|
@@ -381,18 +393,22 @@ class WWID
|
|
381
393
|
opt[:tag_filter] ||= false
|
382
394
|
opt[:tags_color] ||= false
|
383
395
|
opt[:times] ||= false
|
384
|
-
|
396
|
+
# opt[:highlight] ||= true
|
397
|
+
section = ""
|
385
398
|
if opt[:section].nil?
|
386
|
-
|
399
|
+
section = choose_section
|
400
|
+
opt[:section] = @content[section]
|
387
401
|
elsif opt[:section].class == String
|
388
402
|
if opt[:section] =~ /^all$/i
|
389
403
|
combined = {'items' => []}
|
390
404
|
@content.each {|k,v|
|
391
405
|
combined['items'] += v['items']
|
392
406
|
}
|
407
|
+
section = opt[:tag_filter] ? opt[:tag_filter]['tags'].map {|tag| "@#{tag}"}.join(" + ") : "doing"
|
393
408
|
opt[:section] = combined
|
394
409
|
else
|
395
|
-
|
410
|
+
section = guess_section(opt[:section])
|
411
|
+
opt[:section] = @content[section]
|
396
412
|
end
|
397
413
|
end
|
398
414
|
|
@@ -431,6 +447,7 @@ class WWID
|
|
431
447
|
items.delete_if {|item|
|
432
448
|
item['date'] < Date.today.to_time
|
433
449
|
}.reverse!
|
450
|
+
section = Time.now.strftime('%A, %B %d')
|
434
451
|
else
|
435
452
|
if opt[:age] =~ /oldest/i
|
436
453
|
items = items[0..count]
|
@@ -445,20 +462,71 @@ class WWID
|
|
445
462
|
|
446
463
|
out = ""
|
447
464
|
|
448
|
-
if opt[:
|
449
|
-
output
|
465
|
+
if opt[:output]
|
466
|
+
raise "Unknown output format" unless opt[:output] =~ /(html|csv)/
|
467
|
+
end
|
468
|
+
|
469
|
+
if opt[:output] == "csv"
|
470
|
+
output = [CSV.generate_line(['date','title','note'])]
|
450
471
|
items.each {|i|
|
451
472
|
note = ""
|
452
473
|
if i['note']
|
453
474
|
arr = i['note'].map{|line| line.strip}.delete_if{|e| e =~ /^\s*$/}
|
454
475
|
note = arr.join("\n") unless arr.nil?
|
455
476
|
end
|
456
|
-
output.push([i['date'],i['title'],note]
|
477
|
+
output.push(CSV.generate_line([i['date'],i['title'],note]))
|
457
478
|
}
|
458
|
-
out = output.join()
|
459
|
-
|
479
|
+
out = output.join("")
|
480
|
+
elsif opt[:output] == "html"
|
481
|
+
page_title = section
|
482
|
+
items_out = []
|
483
|
+
items.each {|i|
|
484
|
+
# if i.has_key?('note')
|
485
|
+
# note = '<span class="note">' + i['note'].map{|n| n.strip }.join('<br>') + '</span>'
|
486
|
+
# else
|
487
|
+
# note = ''
|
488
|
+
# end
|
489
|
+
items_out << {
|
490
|
+
:date => i['date'].strftime('%a %-I:%M%p'),
|
491
|
+
:title => i['title'].gsub(/(@[^ \(]+(\(.*?\))?)/is,'<span class="tag">\1</span>').strip, #+ " #{note}"
|
492
|
+
:note => i['note']
|
493
|
+
}
|
494
|
+
}
|
495
|
+
style = "body{background:#faf9f5;color:#333;font-family:Palatino,Georgia,serif;font-size:16px;line-height:120%;text-align:justify;padding:20px}h1{text-align:left;position:relative;left:220px;margin-bottom:1em}ul{list-style-position:outside;position:relative;left:170px;margin-right:170px;text-align:left}ul li{list-style-type:none;border-left:solid 1px #ccc;padding-left:10px;line-height:1.75}ul li .date{font-size:14px;position:absolute;left:-82px;color:#7d9ca2;text-align:right;width:110px;line-height:2}ul li .tag{color:#999}ul li .note{display:block;color:#666;padding:0 0 0 22px;line-height:1.4;font-size:15px}ul li .note:before{content:'\\25BA';font-weight:300;position:absolute;left:40px;font-size:8px;color:#aaa;line-height:3}ul li:hover .note{display:block}"
|
496
|
+
template =<<EOT
|
497
|
+
!!!
|
498
|
+
%html
|
499
|
+
%head
|
500
|
+
%meta{"charset" => "utf-8"}/
|
501
|
+
%meta{"content" => "IE=edge,chrome=1", "http-equiv" => "X-UA-Compatible"}/
|
502
|
+
%title what are you doing?
|
503
|
+
%style= @style
|
504
|
+
%body
|
505
|
+
%header
|
506
|
+
%h1= @page_title
|
507
|
+
%article
|
508
|
+
%ul
|
509
|
+
- @items.each do |i|
|
510
|
+
%li
|
511
|
+
%span.date= i[:date]
|
512
|
+
= i[:title]
|
513
|
+
- if i[:note]
|
514
|
+
%span.note= i[:note].map{|n| n.strip }.join('<br>')
|
515
|
+
EOT
|
516
|
+
engine = Haml::Engine.new(template)
|
517
|
+
puts engine.render(Object.new, { :@items => items_out, :@page_title => page_title, :@style => style })
|
460
518
|
|
519
|
+
else
|
461
520
|
items.each {|item|
|
521
|
+
|
522
|
+
if opt[:highlight] && item['title'] =~ /@#{@config['marker_tag']}\b/i
|
523
|
+
flag = colors[@config['marker_color']]
|
524
|
+
reset = colors['default']
|
525
|
+
else
|
526
|
+
flag = ""
|
527
|
+
reset = ""
|
528
|
+
end
|
529
|
+
|
462
530
|
if (item.has_key?('note') && !item['note'].empty?) && @config[:include_notes]
|
463
531
|
note_lines = item['note'].delete_if{|line| line =~ /^\s*$/ }.map{|line| "\t\t" + line.sub(/^\t\t/,'') }
|
464
532
|
if opt[:wrap_width] && opt[:wrap_width] > 0
|
@@ -500,11 +568,12 @@ class WWID
|
|
500
568
|
item['date'].strftime('%b %d %Y, %-I:%M%P')
|
501
569
|
end
|
502
570
|
}
|
571
|
+
|
503
572
|
output.sub!(/%title/) {|m|
|
504
573
|
if opt[:wrap_width] && opt[:wrap_width] > 0
|
505
|
-
item['title'].gsub(/(.{1,#{opt[:wrap_width]}})(\s+|\Z)/, "\\1\n\t ").
|
574
|
+
flag+item['title'].gsub(/(.{1,#{opt[:wrap_width]}})(\s+|\Z)/, "\\1\n\t ").chomp+reset
|
506
575
|
else
|
507
|
-
item['title'].
|
576
|
+
flag+item['title'].chomp+reset
|
508
577
|
end
|
509
578
|
}
|
510
579
|
if opt[:tags_color]
|
@@ -528,20 +597,94 @@ class WWID
|
|
528
597
|
return out
|
529
598
|
end
|
530
599
|
|
531
|
-
def archive(section=
|
600
|
+
def archive(section="Currently",count=5,destination=nil,tags=nil,bool=nil,export=nil)
|
601
|
+
|
532
602
|
section = choose_section if section.nil? || section =~ /choose/i
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
603
|
+
archive_all = section =~ /all/i # && !(tags.nil? || tags.empty?)
|
604
|
+
section = guess_section(section) unless archive_all
|
605
|
+
|
606
|
+
if destination =~ /archive/i && !sections.include?("Archive")
|
607
|
+
add_section("Archive")
|
608
|
+
end
|
609
|
+
|
610
|
+
destination = guess_section(destination)
|
611
|
+
|
612
|
+
if sections.include?(destination) && (sections.include?(section) || archive_all)
|
613
|
+
if archive_all
|
614
|
+
to_archive = sections.dup
|
615
|
+
to_archive.delete(destination)
|
616
|
+
to_archive.each {|source,v|
|
617
|
+
do_archive(source, destination, { :count => count, :tags => tags, :bool => bool, :label => true })
|
618
|
+
}
|
619
|
+
else
|
620
|
+
do_archive(section, destination, { :count => count, :tags => tags, :bool => bool, :label => true })
|
621
|
+
end
|
622
|
+
|
623
|
+
write(doing_file)
|
624
|
+
else
|
625
|
+
raise "Either source or destination does not exist"
|
541
626
|
end
|
542
627
|
end
|
543
628
|
|
629
|
+
def do_archive(section, destination, opt={})
|
630
|
+
count = opt[:count] || 5
|
631
|
+
tags = opt[:tags] || []
|
632
|
+
bool = opt[:bool] || "AND"
|
633
|
+
label = opt[:label] || false
|
544
634
|
|
635
|
+
items = @content[section]['items']
|
636
|
+
moved_items = []
|
637
|
+
|
638
|
+
if tags && !tags.empty?
|
639
|
+
items.delete_if {|item|
|
640
|
+
if bool =~ /(AND|ALL)/
|
641
|
+
score = 0
|
642
|
+
tags.each {|tag|
|
643
|
+
score += 1 if item['title'] =~ /@#{tag}/i
|
644
|
+
}
|
645
|
+
res = score < tags.length
|
646
|
+
moved_items.push(item) if res
|
647
|
+
res
|
648
|
+
elsif bool =~ /NONE/
|
649
|
+
del = false
|
650
|
+
tags.each {|tag|
|
651
|
+
del = true if item['title'] =~ /@#{tag}/i
|
652
|
+
}
|
653
|
+
moved_items.push(item) if del
|
654
|
+
del
|
655
|
+
elsif bool =~ /(OR|ANY)/
|
656
|
+
del = true
|
657
|
+
tags.each {|tag|
|
658
|
+
del = false if item['title'] =~ /@#{tag}/i
|
659
|
+
}
|
660
|
+
moved_items.push(item) if del
|
661
|
+
del
|
662
|
+
end
|
663
|
+
}
|
664
|
+
moved_items.each {|item|
|
665
|
+
if label
|
666
|
+
item['title'] += " @from(#{section})" unless section == "Currently" || item['title'] =~ /@from\(/
|
667
|
+
end
|
668
|
+
}
|
669
|
+
@content[section]['items'] = moved_items
|
670
|
+
@content[destination]['items'] += items
|
671
|
+
else
|
672
|
+
|
673
|
+
return if items.length < count
|
674
|
+
if count == 0
|
675
|
+
@content[section]['items'] = []
|
676
|
+
else
|
677
|
+
@content[section]['items'] = items[0..count-1]
|
678
|
+
end
|
679
|
+
|
680
|
+
items.each{|item|
|
681
|
+
if label
|
682
|
+
item['title'] += " @from(#{section})" unless section == "Currently"
|
683
|
+
end
|
684
|
+
}
|
685
|
+
@content[destination]['items'] += items[count..-1]
|
686
|
+
end
|
687
|
+
end
|
545
688
|
|
546
689
|
def colors
|
547
690
|
color = {}
|
@@ -588,26 +731,28 @@ class WWID
|
|
588
731
|
list_section({:section => @current_section, :wrap_width => cfg['wrap_width'], :count => 0, :format => cfg['date_format'], :template => cfg['template'], :order => order})
|
589
732
|
end
|
590
733
|
|
591
|
-
def today(times=
|
734
|
+
def today(times=true,output=nil)
|
592
735
|
cfg = @config['templates']['today']
|
593
|
-
list_section({:section => @current_section, :wrap_width => cfg['wrap_width'], :count => 0, :format => cfg['date_format'], :template => cfg['template'], :order => "asc", :today => true, :times => times})
|
736
|
+
list_section({:section => @current_section, :wrap_width => cfg['wrap_width'], :count => 0, :format => cfg['date_format'], :template => cfg['template'], :order => "asc", :today => true, :times => times, :output => output})
|
594
737
|
end
|
595
738
|
|
596
|
-
def recent(count=10,section=nil)
|
739
|
+
def recent(count=10,section=nil,opt={})
|
740
|
+
times = opt[:t] || true
|
597
741
|
cfg = @config['templates']['recent']
|
598
742
|
section ||= @current_section
|
599
743
|
section = guess_section(section)
|
600
|
-
list_section({:section => section, :wrap_width => cfg['wrap_width'], :count => count, :format => cfg['date_format'], :template => cfg['template'], :order => "asc"})
|
744
|
+
list_section({:section => section, :wrap_width => cfg['wrap_width'], :count => count, :format => cfg['date_format'], :template => cfg['template'], :order => "asc", :times => times })
|
601
745
|
end
|
602
746
|
|
603
|
-
def last
|
747
|
+
def last(times=true)
|
604
748
|
cfg = @config['templates']['last']
|
605
|
-
list_section({:section => @current_section, :wrap_width => cfg['wrap_width'], :count => 1, :format => cfg['date_format'], :template => cfg['template']})
|
749
|
+
list_section({:section => @current_section, :wrap_width => cfg['wrap_width'], :count => 1, :format => cfg['date_format'], :template => cfg['template'], :times => times})
|
606
750
|
end
|
607
751
|
|
608
752
|
def tag_times
|
609
753
|
output = []
|
610
|
-
return "" if @timers.length == 0
|
754
|
+
# return "" if @timers.length == 0
|
755
|
+
|
611
756
|
max = @timers.keys.sort_by {|k| k.length }.reverse[0].length + 1
|
612
757
|
|
613
758
|
total = @timers.delete("All")
|
@@ -619,7 +764,10 @@ class WWID
|
|
619
764
|
end
|
620
765
|
output.push("#{k}:#{spacer}#{"%02d:%02d:%02d" % fmt_time(v)}")
|
621
766
|
}
|
622
|
-
|
767
|
+
|
768
|
+
output = output.empty? ? "" : "\n--- Tag Totals ---\n" + output.join("\n")
|
769
|
+
output += "\n\nTotal tracked: #{"%02d:%02d:%02d" % fmt_time(total)}\n"
|
770
|
+
output
|
623
771
|
end
|
624
772
|
|
625
773
|
private
|
@@ -666,7 +814,6 @@ end
|
|
666
814
|
|
667
815
|
|
668
816
|
|
669
|
-
|
670
817
|
# infile = "~/Dropbox/nvALT2.2/?? What was I doing.md"
|
671
818
|
|
672
819
|
# wwid = WWID.new(infile)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: doing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.5pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brett Terpstra
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-03-
|
11
|
+
date: 2014-03-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -72,6 +72,20 @@ dependencies:
|
|
72
72
|
- - '='
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: 2.9.0
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: haml
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - '='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: 4.0.3
|
82
|
+
type: :runtime
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - '='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 4.0.3
|
75
89
|
- !ruby/object:Gem::Dependency
|
76
90
|
name: chronic
|
77
91
|
requirement: !ruby/object:Gem::Requirement
|
@@ -130,9 +144,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
130
144
|
version: '0'
|
131
145
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
132
146
|
requirements:
|
133
|
-
- - '
|
147
|
+
- - '>'
|
134
148
|
- !ruby/object:Gem::Version
|
135
|
-
version:
|
149
|
+
version: 1.3.1
|
136
150
|
requirements: []
|
137
151
|
rubyforge_project:
|
138
152
|
rubygems_version: 2.2.2
|