doing 1.0.82 → 1.0.83

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
  SHA256:
3
- metadata.gz: 146bc31206860d02e7f7e3d3d04b12cd84ecf794171af8f25ca679f49c6a98d0
4
- data.tar.gz: 994568054f7f905bbe6a1982b00be636a68bac2719b4f6740ce04bf5cbcb208a
3
+ metadata.gz: fb85f27f305f246d4ab182268c9e5188da67f22fde46d3ee4ae716996c78b2c3
4
+ data.tar.gz: 7b302748d9837511adc77679fd619c6daf85b2f7e15f541d530c8cc211e0aac3
5
5
  SHA512:
6
- metadata.gz: d3c606a1bf94fc65241841ca4e9899488f8271569492fb33d4ecf49c46007bb1f678c5d6995656a17fbd003d387942bf43b0575b09d9a78bfc64852504224586
7
- data.tar.gz: 5032b06cc50cc867e29f99973b6f03e4256f746f5643db7275a17621252db5e825fb1aa1b07439c0a3f087a2cfe96f6bc3a9966c98693f8a3a994880c81b6857
6
+ metadata.gz: dbf5e04626a97e5287c2417cf5afffd6516860a1fa5f3ed64e93fe15bdc62b85f045d0a54adc08c774b4d711add29f02799cf3d4a2c22853e1273a691d0a9f00
7
+ data.tar.gz: 87bf6eac2e770b161c8ae4fd2fee4adea5ed261b828f2142997858393a627e0d36788981fe52a4c66486f442da2de349ce1ac157732d824b0ef633e4dcbdc703
data/README.md CHANGED
@@ -27,7 +27,7 @@ If there's something I want to look at later but doesn't need to be added to a t
27
27
 
28
28
  ## Installation
29
29
 
30
- The current version of `doing` is <!--VER-->1.0.79<!--END VER-->.
30
+ The current version of `doing` is <!--VER-->1.0.82<!--END VER-->.
31
31
 
32
32
  $ [sudo] gem install doing
33
33
 
@@ -245,7 +245,7 @@ You can create your own "views" in the `~/.doingrc` file and view them with `doi
245
245
 
246
246
  views:
247
247
  old:
248
- section: Old
248
+ section: Archive
249
249
  count: 5
250
250
  wrap_width: 0
251
251
  date_format: '%F %_I:%M%P'
@@ -253,6 +253,10 @@ You can create your own "views" in the `~/.doingrc` file and view them with `doi
253
253
  order: asc
254
254
  tags: done finished cancelled
255
255
  tags_bool: ANY
256
+ only_timed: false
257
+ tag_sort: time
258
+ tag_order: asc
259
+ totals: true
256
260
 
257
261
  You can add additional custom views. Just nest them under the `views` key (indented two spaces from the edge). Multiple views would look like this:
258
262
 
@@ -276,7 +280,9 @@ You can add new sections with `doing add_section section_name`. You can also cre
276
280
 
277
281
  The `tags` and `tags_bool` keys allow you to specify tags that the view is filtered by. You can list multiple tags separated by spaces, and then use `tags_bool` to specify `ALL`, `ANY`, or `NONE` to determine how it handles the multiple tags.
278
282
 
279
- The `order` key defines the sort order of the output. This is applied _after_ the tasks are retrieved and cut off at the maximum number specified in `count`.
283
+ The `order` key defines the sort order of the output (asc or desc). This is applied _after_ the tasks are retrieved and cut off at the maximum number specified in `count`.
284
+
285
+ You can include tag timers and totals in the output with `totals: true`. Control tag output using `tag_sort` (name or title) and `tag_order` (asc or desc). You can also output only timed entries using `only_timed: true`. All of these options can be overridden using flags on the `doing view` command.
280
286
 
281
287
  Regarding colors, you can use them to create very nice displays if you're outputting to a color terminal. Example:
282
288
 
@@ -291,7 +297,7 @@ Outputs:
291
297
 
292
298
  ![](http://ckyp.us/XKpj+)
293
299
 
294
- You can also specify a default output format for a view. Most of the optional output formats override the template specification (`html`, `csv`, `json`). If the `view` command is used with the `-o` flag, it will override what's specified in the file.
300
+ You can also specify a default output format for a view. Most of the optional output formats override the template specification (`html`, `csv`, `json`). If the `view` command is used with the `-o` flag, it will override what's specified for the view in the config.
295
301
 
296
302
  ### Colors
297
303
 
data/bin/doing CHANGED
@@ -1344,13 +1344,14 @@ command :colors do |c|
1344
1344
  end
1345
1345
 
1346
1346
  desc 'Display a user-created view'
1347
+ long_desc 'Command line options override associated view settings'
1347
1348
  arg_name 'VIEW_NAME'
1348
1349
  command :view do |c|
1349
- c.desc 'Section (override view settings)'
1350
+ c.desc 'Section'
1350
1351
  c.arg_name 'NAME'
1351
1352
  c.flag %i[s section]
1352
1353
 
1353
- c.desc 'Count to display (override view settings)'
1354
+ c.desc 'Count to display'
1354
1355
  c.arg_name 'COUNT'
1355
1356
  c.flag %i[c count], must_match: /^\d+$/, type: Integer
1356
1357
 
@@ -1368,12 +1369,14 @@ command :view do |c|
1368
1369
  c.switch [:color], default_value: true, negatable: true
1369
1370
 
1370
1371
  c.desc 'Sort tags by (name|time)'
1371
- default = 'time'
1372
- default = wwid.config['tag_sort'] if wwid.config.key?('tag_sort')
1373
1372
  c.arg_name 'KEY'
1374
- c.flag [:tag_sort], must_match: /^(?:name|time)$/i, default_value: default
1373
+ c.flag [:tag_sort], must_match: /^(?:name|time)$/i
1375
1374
 
1376
- c.desc 'Only show items with recorded time intervals'
1375
+ c.desc 'Tag sort direction (asc|desc)'
1376
+ c.arg_name 'DIRECTION'
1377
+ c.flag [:tag_order], must_match: /^(?:a(?:sc)?|d(?:esc)?)$/i
1378
+
1379
+ c.desc 'Only show items with recorded time intervals (override view settings)'
1377
1380
  c.switch [:only_timed], default_value: false, negatable: false
1378
1381
 
1379
1382
  c.action do |_global_options, options, args|
@@ -1422,10 +1425,31 @@ command :view do |c|
1422
1425
  end
1423
1426
  order = view.key?('order') ? view['order'] : 'asc'
1424
1427
 
1425
- options[:t] = true if options[:totals]
1428
+ totals = if options[:totals]
1429
+ true
1430
+ else
1431
+ view.key?('totals') ? view['totals'] : false
1432
+ end
1433
+
1434
+ options[:t] = true if totals
1426
1435
  options[:output]&.downcase!
1427
- options[:sort_tags] = options[:tag_sort] =~ /^n/i
1428
1436
 
1437
+ options[:sort_tags] = if options[:tag_sort]
1438
+ options[:tag_sort] =~ /^n/i ? true : false
1439
+ elsif view.key?('tag_sort')
1440
+ view['tag_sort'] =~ /^n/i ? true : false
1441
+ else
1442
+ false
1443
+ end
1444
+
1445
+ tag_order = if options[:tag_order]
1446
+ options[:tag_order] =~ /^d/i ? 'desc' : 'asc'
1447
+ elsif view.key?('tag_order')
1448
+ view['tag_order'] =~ /^d/i ? 'desc' : 'asc'
1449
+ else
1450
+ 'asc'
1451
+ end
1452
+ warn "TAG ORDER: #{options[:tag_order]}"
1429
1453
  opts = {
1430
1454
  count: count,
1431
1455
  format: format,
@@ -1436,10 +1460,11 @@ command :view do |c|
1436
1460
  section: section,
1437
1461
  sort_tags: options[:sort_tags],
1438
1462
  tag_filter: tag_filter,
1463
+ tag_order: tag_order,
1439
1464
  tags_color: tags_color,
1440
1465
  template: template,
1441
1466
  times: options[:t],
1442
- totals: options[:totals]
1467
+ totals: totals
1443
1468
  }
1444
1469
 
1445
1470
  puts wwid.list_section(opts)
data/lib/doing/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Doing
2
- VERSION = '1.0.82'
2
+ VERSION = '1.0.83'
3
3
  end
data/lib/doing/wwid.rb CHANGED
@@ -84,6 +84,7 @@ class WWID
84
84
  ##
85
85
  def configure(opt = {})
86
86
  @timers = {}
87
+ @recorded_items = []
87
88
  opt[:ignore_local] ||= false
88
89
 
89
90
  @config_file ||= File.join(@user_home, @default_config_file)
@@ -583,17 +584,17 @@ class WWID
583
584
  end
584
585
 
585
586
  def same_time?(item_a, item_b)
586
- item_a['date'] == item_b['date'] ? get_interval(item_a, false) == get_interval(item_b, false) : false
587
+ item_a['date'] == item_b['date'] ? get_interval(item_a, formatted: false, record: false) == get_interval(item_b, formatted: false, record: false) : false
587
588
  end
588
589
 
589
590
  def overlapping_time?(item_a, item_b)
590
591
  return true if same_time?(item_a, item_b)
591
592
 
592
593
  start_a = item_a['date']
593
- interval = get_interval(item_a, false)
594
+ interval = get_interval(item_a, formatted: false, record: false)
594
595
  end_a = interval ? start_a + interval.to_i : start_a
595
596
  start_b = item_b['date']
596
- interval = get_interval(item_b, false)
597
+ interval = get_interval(item_b, formatted: false, record: false)
597
598
  end_b = interval ? start_b + interval.to_i : start_b
598
599
  (start_a >= start_b && start_a <= end_b) || (end_a >= start_b && end_a <= end_b) || (start_a < start_b && end_a > end_b)
599
600
  end
@@ -1569,20 +1570,21 @@ class WWID
1569
1570
  def list_section(opt = {})
1570
1571
  opt[:count] ||= 0
1571
1572
  count = opt[:count] - 1
1572
- opt[:section] ||= nil
1573
- opt[:format] ||= @default_date_format
1574
- opt[:template] ||= @default_template
1575
1573
  opt[:age] ||= 'newest'
1574
+ opt[:date_filter] ||= []
1575
+ opt[:format] ||= @default_date_format
1576
+ opt[:only_timed] ||= false
1576
1577
  opt[:order] ||= 'desc'
1577
- opt[:today] ||= false
1578
+ opt[:search] ||= false
1579
+ opt[:section] ||= nil
1580
+ opt[:sort_tags] ||= false
1578
1581
  opt[:tag_filter] ||= false
1582
+ opt[:tag_order] ||= 'asc'
1579
1583
  opt[:tags_color] ||= false
1584
+ opt[:template] ||= @default_template
1580
1585
  opt[:times] ||= false
1586
+ opt[:today] ||= false
1581
1587
  opt[:totals] ||= false
1582
- opt[:sort_tags] ||= false
1583
- opt[:search] ||= false
1584
- opt[:only_timed] ||= false
1585
- opt[:date_filter] ||= []
1586
1588
 
1587
1589
  # opt[:highlight] ||= true
1588
1590
  section = ''
@@ -1635,7 +1637,7 @@ class WWID
1635
1637
 
1636
1638
  if opt[:only_timed]
1637
1639
  items.delete_if do |item|
1638
- get_interval(item) == false
1640
+ get_interval(item, record: false) == false
1639
1641
  end
1640
1642
  end
1641
1643
 
@@ -1670,7 +1672,7 @@ class WWID
1670
1672
  arr = i['note'].map { |line| line.strip }.delete_if { |e| e =~ /^\s*$/ }
1671
1673
  note = arr.join("\n") unless arr.nil?
1672
1674
  end
1673
- interval = get_interval(i, false) if i['title'] =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
1675
+ interval = get_interval(i, formatted: false) if i['title'] =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
1674
1676
  interval ||= 0
1675
1677
  output.push(CSV.generate_line([i['date'], i['title'], note, interval, i['section']]))
1676
1678
  end
@@ -1689,7 +1691,7 @@ class WWID
1689
1691
  end
1690
1692
  if i['title'] =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
1691
1693
  end_date = Time.parse(Regexp.last_match(1))
1692
- interval = get_interval(i, false)
1694
+ interval = get_interval(i, formatted: false)
1693
1695
  end
1694
1696
  end_date ||= ''
1695
1697
  interval ||= 0
@@ -1738,7 +1740,7 @@ class WWID
1738
1740
  out = {
1739
1741
  'section' => section,
1740
1742
  'items' => items_out,
1741
- 'timers' => tag_times('json', opt[:sort_tags])
1743
+ 'timers' => tag_times(format: 'json', sort_by_name: opt[:sort_tags], sort_order: opt[:tag_order])
1742
1744
  }.to_json
1743
1745
  elsif opt[:output] == 'timeline'
1744
1746
  template = <<~EOTEMPLATE
@@ -1819,7 +1821,7 @@ class WWID
1819
1821
  css_template
1820
1822
  end
1821
1823
 
1822
- totals = opt[:totals] ? tag_times('html', opt[:sort_tags]) : ''
1824
+ totals = opt[:totals] ? tag_times(format: 'html', sort_by_name: opt[:sort_tags], sort_order: opt[:tag_order]) : ''
1823
1825
  engine = Haml::Engine.new(template)
1824
1826
  out = engine.render(Object.new,
1825
1827
  { :@items => items_out, :@page_title => page_title, :@style => style, :@totals => totals })
@@ -1860,7 +1862,7 @@ class WWID
1860
1862
 
1861
1863
  output.sub!(/%date/, item['date'].strftime(opt[:format]))
1862
1864
 
1863
- interval = get_interval(item) if item['title'] =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
1865
+ interval = get_interval(item, record: true) if item['title'] =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
1864
1866
  interval ||= ''
1865
1867
  output.sub!(/%interval/, interval)
1866
1868
 
@@ -1910,7 +1912,8 @@ class WWID
1910
1912
 
1911
1913
  out += "#{output}\n"
1912
1914
  end
1913
- out += tag_times('text', opt[:sort_tags]) if opt[:totals]
1915
+
1916
+ out += tag_times(format: 'text', sort_by_name: opt[:sort_tags], sort_order: opt[:tag_order]) if opt[:totals]
1914
1917
  end
1915
1918
  out
1916
1919
  end
@@ -2173,11 +2176,15 @@ class WWID
2173
2176
  end
2174
2177
 
2175
2178
  ##
2176
- ## @brief Get total elapsed time for all tags in selection
2179
+ ## @brief Get total elapsed time for all tags in
2180
+ ## selection
2177
2181
  ##
2178
- ## @param format (String) return format (html, json, or text)
2182
+ ## @param format (String) return format (html,
2183
+ ## json, or text)
2184
+ ## @param sort_by_name (Boolean) Sort by name if true, otherwise by time
2185
+ ## @param sort_order (String) The sort order (asc or desc)
2179
2186
  ##
2180
- def tag_times(format = 'text', sort_by_name = false)
2187
+ def tag_times(format: 'text', sort_by_name: false, sort_order: 'asc')
2181
2188
  return '' if @timers.empty?
2182
2189
 
2183
2190
  max = @timers.keys.sort_by { |k| k.length }.reverse[0].length + 1
@@ -2186,11 +2193,13 @@ class WWID
2186
2193
 
2187
2194
  tags_data = @timers.delete_if { |_k, v| v == 0 }
2188
2195
  sorted_tags_data = if sort_by_name
2189
- tags_data.sort_by { |k, _v| k }.reverse
2196
+ tags_data.sort_by { |k, _v| k }
2190
2197
  else
2191
2198
  tags_data.sort_by { |_k, v| v }
2192
2199
  end
2193
2200
 
2201
+ sorted_tags_data.reverse! if sort_order =~ /^asc/i
2202
+
2194
2203
  if format == 'html'
2195
2204
  output = <<EOS
2196
2205
  <table>
@@ -2324,19 +2333,20 @@ EOS
2324
2333
  ## @param item (Hash) The entry
2325
2334
  ## @param formatted (Bool) Return human readable time (default seconds)
2326
2335
  ##
2327
- def get_interval(item, formatted = true)
2336
+ def get_interval(item, formatted: true, record: true)
2328
2337
  done = nil
2329
2338
  start = nil
2330
2339
 
2331
2340
  if @interval_cache.keys.include? item['title']
2332
2341
  seconds = @interval_cache[item['title']]
2342
+ record_tag_times(item, seconds) if record
2333
2343
  return seconds > 0 ? '%02d:%02d:%02d' % fmt_time(seconds) : false
2334
2344
  end
2335
2345
 
2336
2346
  if item['title'] =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/
2337
2347
  done = Time.parse(Regexp.last_match(1))
2338
2348
  else
2339
- return nil
2349
+ return false
2340
2350
  end
2341
2351
 
2342
2352
  start = if item['title'] =~ /@start\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/
@@ -2347,20 +2357,34 @@ EOS
2347
2357
 
2348
2358
  seconds = (done - start).to_i
2349
2359
 
2360
+ if record
2361
+ record_tag_times(item, seconds)
2362
+ end
2363
+
2364
+ @interval_cache[item['title']] = seconds
2365
+
2366
+ return seconds > 0 ? seconds : false unless formatted
2367
+
2368
+ seconds > 0 ? '%02d:%02d:%02d' % fmt_time(seconds) : false
2369
+ end
2370
+
2371
+ ##
2372
+ ## @brief Record times for item tags
2373
+ ##
2374
+ ## @param item The item
2375
+ ##
2376
+ def record_tag_times(item, seconds)
2377
+ return if @recorded_items.include?(item)
2378
+
2350
2379
  item['title'].scan(/(?mi)@(\S+?)(\(.*\))?(?=\s|$)/).each do |m|
2351
2380
  k = m[0] == 'done' ? 'All' : m[0].downcase
2352
- if @timers.has_key?(k)
2381
+ if @timers.key?(k)
2353
2382
  @timers[k] += seconds
2354
2383
  else
2355
2384
  @timers[k] = seconds
2356
2385
  end
2386
+ @recorded_items.push(item)
2357
2387
  end
2358
-
2359
- @interval_cache[item['title']] = seconds
2360
-
2361
- return seconds unless formatted
2362
-
2363
- seconds > 0 ? '%02d:%02d:%02d' % fmt_time(seconds) : false
2364
2388
  end
2365
2389
 
2366
2390
  ##
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: 1.0.82
4
+ version: 1.0.83
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-26 00:00:00.000000000 Z
11
+ date: 2021-10-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake