doing 0.2.4 → 0.2.5pre
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 +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
|