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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9113d5736076e7608e42c328d3bc6a9f6edb517e
4
- data.tar.gz: 793034d75510f42fa2c9f2e3f75d26156fef4d51
3
+ metadata.gz: 8806f026f8106baa4c033a2d30675e0f3c30afea
4
+ data.tar.gz: 77139cb8ae62cc18311d5fcd7c27a725806375c9
5
5
  SHA512:
6
- metadata.gz: bd187715ead8168b92c2a70ebe53d68d95271a241524a1011c82c9358cae43ed0766dea0b1fe73c469d112435921342e2fb9811af2835f039d9ab1445519196f
7
- data.tar.gz: 11c41e6db6c47490ff82b922a262df3292808e6b5736babf3d12a28de96075f91322da61f882c73178a7b9240c82c8056f7f99180bee8c309d1dc852f7427ddc
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 all but the most recent 5 entries to the Archive section
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
- Add basic command line completion for Bash with [this gist](https://gist.github.com/fcrespo82/9609318).
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(#{Time.now.strftime('%F %R')})"
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(#{Time.now.strftime('%F %R')})"
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(#{Time.now.strftime('%F %R')})"
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 csv'
290
- c.default_value false
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 => false
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], :csv => options[:csv], :times => options[:t]})
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
- puts wwid.recent(count,section.cap_first)
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 => false
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]).strip
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 csv'
424
- c.default_value 'false'
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 => false
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, :csv => options[:csv], :tags_color => tags_color, :times => options[:t] })
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 all but the most recent 5 entries in a section to Archive'
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
- section = args.join(" ").cap_first
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
 
@@ -6,6 +6,7 @@ require 'pp'
6
6
  require 'csv'
7
7
  require 'tempfile'
8
8
  require 'chronic'
9
+ require 'haml'
9
10
  require 'doing/wwid.rb'
10
11
 
11
12
  DOING_CONFIG = "~/.doingrc"
@@ -1,3 +1,3 @@
1
1
  module Doing
2
- VERSION = '0.2.4'
2
+ VERSION = '0.2.5pre'
3
3
  end
@@ -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
- sections.each {|section| return section if frag.downcase == section.downcase}
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
- raise "Invalid section: #{frag}"
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 "Invalid view: #{frag}"
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}(#{Time.now.strftime('%F %R')})"
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 + @content['Archive']['items']
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
- opt[:section] = @content[choose_section]
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
- opt[:section] = @content[guess_section(opt[:section])]
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[:csv]
449
- output = [['date','title','note'].to_csv]
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].to_csv)
477
+ output.push(CSV.generate_line([i['date'],i['title'],note]))
457
478
  }
458
- out = output.join()
459
- else
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 ").strip
574
+ flag+item['title'].gsub(/(.{1,#{opt[:wrap_width]}})(\s+|\Z)/, "\\1\n\t ").chomp+reset
506
575
  else
507
- item['title'].strip
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=nil,count=10)
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
- section = guess_section(section)
534
- if sections.include?(section)
535
- items = @content[section]['items']
536
- return if items.length < count
537
- @content[section]['items'] = items[0..count-1]
538
- add_section('Archive') unless sections.include?('Archive')
539
- @content['Archive']['items'] += items[count..-1]
540
- write(@doing_file)
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=false)
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
- output.empty? ? "" : "\n--- Tag Totals ---\n" + output.join("\n") + "\n\nTotal tracked: #{"%02d:%02d:%02d" % fmt_time(total)}\n"
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
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-19 00:00:00.000000000 Z
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: '0'
149
+ version: 1.3.1
136
150
  requirements: []
137
151
  rubyforge_project:
138
152
  rubygems_version: 2.2.2