doing 1.0.84 → 1.0.88
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -1
- data/bin/doing +141 -29
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +107 -23
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd3101f8217fd3af3a0aa5fa57b2b7daf72aeb15510f83a361971403338c293e
|
4
|
+
data.tar.gz: 9bfc051f1129c40db87ac8c31a1eb88d0e9f1b1bc96b6f697e42fdb5351e3d35
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3f7f0fe38daa1f63757dd4b3fb9b6c8a8d55415d47d74c58b2f4450327954381020279e353a44a790142da3802ffc2f6ce1b828ace7fbf3b0042a050674b7084
|
7
|
+
data.tar.gz: c36980be8fb2b8ae10fa750965eb2faa0c3ba4a0230e2e68a12cf09195b4fa16e70851521e0437d5e744fd954b9d1f50b39e7e31c6704592d03d51786be80a99
|
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.
|
30
|
+
The current version of `doing` is <!--VER-->1.0.87<!--END VER-->.
|
31
31
|
|
32
32
|
$ [sudo] gem install doing
|
33
33
|
|
@@ -92,6 +92,7 @@ A basic configuration looks like this:
|
|
92
92
|
date_format: '%_I:%M%P'
|
93
93
|
template: '%date > %title%odnote'
|
94
94
|
wrap_width: 50
|
95
|
+
count: 10
|
95
96
|
autotag:
|
96
97
|
whitelist:
|
97
98
|
- coding
|
@@ -239,6 +240,8 @@ and output my recent entries like this:
|
|
239
240
|
|
240
241
|
$
|
241
242
|
|
243
|
+
The recent template can include a `count` key to specify the number of entries shown when run without an argument. Default is 10.
|
244
|
+
|
242
245
|
### Custom views
|
243
246
|
|
244
247
|
You can create your own "views" in the `~/.doingrc` file and view them with `doing view view_name`. Just add a section like this:
|
@@ -542,6 +545,8 @@ If you have a use for it, you can use `-o csv` on the show or view commands to o
|
|
542
545
|
|
543
546
|
`doing yesterday` is great for stand-ups (thanks to [Sean Collins](https://github.com/sc68cal) for that!). Note that you can show yesterday's activity from an alternate section by using the section name as an argument (e.g. `doing yesterday archive`).
|
544
547
|
|
548
|
+
All of the display commands (view, show, today, yesterday, search) support date ranges in addition to other filtering options. Results can be narrowed to a date/time span using `--before DATE` and `--after DATE`. The `DATE` accepts a natural language string but works best in formats like `10/20/21` or `2021-05-13 3pm` (or shortened to just `5/13 3pm`). For the `today` and `yesterday` commands the `DATE` should just be a time, e.g. `12pm` or `15:00`, and results will be filtered within the timespan for just that day. Both flags are optional, and you can use just `--before` to get everything older than a certain date, or use just `--after` to get everything newer.
|
549
|
+
|
545
550
|
`doing on` allows for full date ranges and filtering. `doing on saturday`, or `doing on one month to today` will give you ranges. You can use the same terms with the `show` command by adding the `-f` or `--from` flag. `doing show @done --from "monday to friday"` will give you all of your completed items for the last week (assuming it's the weekend). There's also `doing since` a simple alias for `doing on PAST_DATE to now`, e.g. `doing since monday`.
|
546
551
|
|
547
552
|
You can also show entries matching a search string with `doing grep` (synonym `doing search`). If you want to search with regular expressions or for an exact match, surround your search query with forward slashes, e.g. `doing search /project name/`. If you pass a search string without slashes, it's treated as a fuzzy search string, meaning matches can be found as long as the characters in the search string are in order and with no more than three other characters between each. By default searches are across all sections, but you can limit it to one with the `-s SECTION_NAME` flag. Searches can be displayed with the default template, or output as HTML, CSV, or JSON.
|
data/bin/doing
CHANGED
@@ -333,10 +333,6 @@ command :later do |c|
|
|
333
333
|
c.desc "Edit entry with #{ENV['EDITOR']}"
|
334
334
|
c.switch %i[e editor], negatable: false, default_value: false
|
335
335
|
|
336
|
-
c.desc 'Edit entry with specified app'
|
337
|
-
c.arg_name 'APP'
|
338
|
-
c.flag %i[a app]
|
339
|
-
|
340
336
|
c.desc 'Backdate start time to date string [4pm|20m|2h|yesterday noon]'
|
341
337
|
c.arg_name 'DATE_STRING'
|
342
338
|
c.flag %i[b back]
|
@@ -353,7 +349,7 @@ command :later do |c|
|
|
353
349
|
date = Time.now
|
354
350
|
end
|
355
351
|
|
356
|
-
if options[:
|
352
|
+
if options[:editor] || (args.empty? && $stdin.stat.size.zero?)
|
357
353
|
exit_now! 'No EDITOR variable defined in environment' if ENV['EDITOR'].nil?
|
358
354
|
|
359
355
|
input = args.empty? ? '' : args.join(' ')
|
@@ -456,7 +452,7 @@ command %i[done did] do |c|
|
|
456
452
|
section = wwid.config['current_section']
|
457
453
|
end
|
458
454
|
|
459
|
-
if options[:
|
455
|
+
if options[:editor]
|
460
456
|
exit_now! 'No EDITOR variable defined in environment' if ENV['EDITOR'].nil?
|
461
457
|
|
462
458
|
input = ''
|
@@ -900,10 +896,22 @@ command :show do |c|
|
|
900
896
|
c.arg_name 'MAX'
|
901
897
|
c.flag %i[c count], default_value: 0
|
902
898
|
|
903
|
-
c.desc 'Age (oldest
|
899
|
+
c.desc 'Age (oldest|newest)'
|
904
900
|
c.arg_name 'AGE'
|
905
901
|
c.flag %i[a age], default_value: 'newest'
|
906
902
|
|
903
|
+
c.desc 'View entries older than date'
|
904
|
+
c.arg_name 'DATE_STRING'
|
905
|
+
c.flag [:before]
|
906
|
+
|
907
|
+
c.desc 'View entries newer than date'
|
908
|
+
c.arg_name 'DATE_STRING'
|
909
|
+
c.flag [:after]
|
910
|
+
|
911
|
+
c.desc 'Search filter, surround with slashes for regex (/query/)'
|
912
|
+
c.arg_name 'QUERY'
|
913
|
+
c.flag [:search]
|
914
|
+
|
907
915
|
c.desc 'Sort order (asc/desc)'
|
908
916
|
c.arg_name 'ORDER'
|
909
917
|
c.flag %i[s sort], must_match: /^[ad].*/i, default_value: 'ASC'
|
@@ -928,6 +936,10 @@ command :show do |c|
|
|
928
936
|
c.arg_name 'KEY'
|
929
937
|
c.flag [:tag_sort], must_match: /^(?:name|time)/i, default_value: default
|
930
938
|
|
939
|
+
c.desc 'Tag sort direction (asc|desc)'
|
940
|
+
c.arg_name 'DIRECTION'
|
941
|
+
c.flag [:tag_order], must_match: /^(?:a(?:sc)?|d(?:esc)?)$/i
|
942
|
+
|
931
943
|
c.desc 'Only show items with recorded time intervals'
|
932
944
|
c.switch [:only_timed], default_value: false, negatable: false
|
933
945
|
|
@@ -983,8 +995,8 @@ command :show do |c|
|
|
983
995
|
}
|
984
996
|
end
|
985
997
|
|
986
|
-
if options[:
|
987
|
-
date_string = options[:
|
998
|
+
if options[:from]
|
999
|
+
date_string = options[:from]
|
988
1000
|
if date_string =~ / (to|through|thru|(un)?til|-+) /
|
989
1001
|
dates = date_string.split(/ (to|through|thru|(un)?til|-+) /)
|
990
1002
|
start = wwid.chronify(dates[0])
|
@@ -997,22 +1009,31 @@ command :show do |c|
|
|
997
1009
|
dates = [start, finish]
|
998
1010
|
end
|
999
1011
|
|
1000
|
-
options[:
|
1012
|
+
options[:times] = true if options[:totals]
|
1001
1013
|
|
1002
1014
|
tags_color = wwid.config.key?('tags_color') ? wwid.config['tags_color'] : nil
|
1003
1015
|
|
1004
1016
|
options[:sort_tags] = options[:tag_sort] =~ /^n/i
|
1017
|
+
tag_order = if options[:tag_order]
|
1018
|
+
options[:tag_order] =~ /^d/i ? 'desc' : 'asc'
|
1019
|
+
else
|
1020
|
+
'asc'
|
1021
|
+
end
|
1005
1022
|
opts = {
|
1006
|
-
|
1023
|
+
after: options[:after],
|
1024
|
+
age: options[:age],
|
1025
|
+
before: options[:before],
|
1007
1026
|
count: options[:c].to_i,
|
1008
1027
|
date_filter: dates,
|
1009
1028
|
highlight: true,
|
1010
1029
|
only_timed: options[:only_timed],
|
1011
1030
|
order: options[:s],
|
1012
1031
|
output: options[:output],
|
1032
|
+
search: options[:search],
|
1013
1033
|
section: section,
|
1014
1034
|
sort_tags: options[:sort_tags],
|
1015
1035
|
tag_filter: tag_filter,
|
1036
|
+
tag_order: tag_order,
|
1016
1037
|
tags_color: tags_color,
|
1017
1038
|
times: options[:t],
|
1018
1039
|
totals: options[:totals]
|
@@ -1034,6 +1055,14 @@ command [:grep, :search] do |c|
|
|
1034
1055
|
c.arg_name 'NAME'
|
1035
1056
|
c.flag %i[s section], default_value: 'All'
|
1036
1057
|
|
1058
|
+
c.desc 'Constrain search to entries older than date'
|
1059
|
+
c.arg_name 'DATE_STRING'
|
1060
|
+
c.flag [:before]
|
1061
|
+
|
1062
|
+
c.desc 'Constrain search to entries newer than date'
|
1063
|
+
c.arg_name 'DATE_STRING'
|
1064
|
+
c.flag [:after]
|
1065
|
+
|
1037
1066
|
c.desc 'Output to export format (csv|html|json|template|timeline)'
|
1038
1067
|
c.arg_name 'FORMAT'
|
1039
1068
|
c.flag %i[o output], must_match: /^(?:template|html|csv|json|timeline)$/i
|
@@ -1058,10 +1087,12 @@ command [:grep, :search] do |c|
|
|
1058
1087
|
|
1059
1088
|
section = wwid.guess_section(options[:s]) if options[:s]
|
1060
1089
|
|
1061
|
-
options[:
|
1090
|
+
options[:times] = true if options[:totals]
|
1062
1091
|
options[:sort_tags] = options[:tag_sort] =~ /^n/i
|
1063
1092
|
|
1064
1093
|
opts = {
|
1094
|
+
after: options[:after],
|
1095
|
+
before: options[:before],
|
1065
1096
|
highlight: true,
|
1066
1097
|
only_timed: options[:only_timed],
|
1067
1098
|
output: options[:output],
|
@@ -1069,7 +1100,7 @@ command [:grep, :search] do |c|
|
|
1069
1100
|
section: section,
|
1070
1101
|
sort_tags: options[:sort_tags],
|
1071
1102
|
tags_color: tags_color,
|
1072
|
-
times: options[:
|
1103
|
+
times: options[:times],
|
1073
1104
|
totals: options[:totals]
|
1074
1105
|
}
|
1075
1106
|
|
@@ -1101,7 +1132,12 @@ command :recent do |c|
|
|
1101
1132
|
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
1102
1133
|
|
1103
1134
|
unless global_options[:version]
|
1104
|
-
|
1135
|
+
if wwid.config['templates']['recent'].key?('count')
|
1136
|
+
config_count = wwid.config['templates']['recent']['count'].to_i
|
1137
|
+
else
|
1138
|
+
config_count = 10
|
1139
|
+
end
|
1140
|
+
count = args.empty? ? config_count : args[0].to_i
|
1105
1141
|
options[:t] = true if options[:totals]
|
1106
1142
|
options[:sort_tags] = options[:tag_sort] =~ /^n/i
|
1107
1143
|
tags_color = wwid.config.key?('tags_color') ? wwid.config['tags_color'] : nil
|
@@ -1141,12 +1177,25 @@ command :today do |c|
|
|
1141
1177
|
c.arg_name 'FORMAT'
|
1142
1178
|
c.flag %i[o output], must_match: /^(?:template|html|csv|json|timeline)$/i
|
1143
1179
|
|
1180
|
+
c.desc 'View entries before specified time (e.g. 8am, 12:30pm, 15:00)'
|
1181
|
+
c.arg_name 'TIME_STRING'
|
1182
|
+
c.flag [:before]
|
1183
|
+
|
1184
|
+
c.desc 'View entries after specified time (e.g. 8am, 12:30pm, 15:00)'
|
1185
|
+
c.arg_name 'TIME_STRING'
|
1186
|
+
c.flag [:after]
|
1187
|
+
|
1144
1188
|
c.action do |_global_options, options, _args|
|
1145
1189
|
options[:t] = true if options[:totals]
|
1146
1190
|
options[:sort_tags] = options[:tag_sort] =~ /^n/i
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1191
|
+
opt = {
|
1192
|
+
after: options[:after],
|
1193
|
+
before: options[:before],
|
1194
|
+
section: options[:section],
|
1195
|
+
sort_tags: options[:sort_tags],
|
1196
|
+
totals: options[:totals]
|
1197
|
+
}
|
1198
|
+
puts wwid.today(options[:times], options[:output], opt).chomp
|
1150
1199
|
end
|
1151
1200
|
end
|
1152
1201
|
|
@@ -1275,10 +1324,33 @@ command :yesterday do |c|
|
|
1275
1324
|
c.arg_name 'KEY'
|
1276
1325
|
c.flag [:tag_sort], must_match: /^(?:name|time)$/i, default_value: default
|
1277
1326
|
|
1327
|
+
c.desc 'View entries before specified time (e.g. 8am, 12:30pm, 15:00)'
|
1328
|
+
c.arg_name 'TIME_STRING'
|
1329
|
+
c.flag [:before]
|
1330
|
+
|
1331
|
+
c.desc 'View entries after specified time (e.g. 8am, 12:30pm, 15:00)'
|
1332
|
+
c.arg_name 'TIME_STRING'
|
1333
|
+
c.flag [:after]
|
1334
|
+
|
1335
|
+
c.desc 'Tag sort direction (asc|desc)'
|
1336
|
+
c.arg_name 'DIRECTION'
|
1337
|
+
c.flag [:tag_order], must_match: /^(?:a(?:sc)?|d(?:esc)?)$/i
|
1338
|
+
|
1278
1339
|
c.action do |_global_options, options, _args|
|
1340
|
+
tag_order = if options[:tag_order]
|
1341
|
+
options[:tag_order] =~ /^d/i ? 'desc' : 'asc'
|
1342
|
+
else
|
1343
|
+
'asc'
|
1344
|
+
end
|
1279
1345
|
options[:sort_tags] = options[:tag_sort] =~ /^n/i
|
1280
|
-
|
1281
|
-
|
1346
|
+
opt = {
|
1347
|
+
after: options[:after],
|
1348
|
+
before: options[:before],
|
1349
|
+
sort_tags: options[:sort_tags],
|
1350
|
+
tag_order: options[:tag_order],
|
1351
|
+
totals: options[:totals]
|
1352
|
+
}
|
1353
|
+
puts wwid.yesterday(options[:section], options[:times], options[:output], opt).chomp
|
1282
1354
|
end
|
1283
1355
|
end
|
1284
1356
|
|
@@ -1321,7 +1393,7 @@ command :last do |c|
|
|
1321
1393
|
|
1322
1394
|
end
|
1323
1395
|
|
1324
|
-
if options[:
|
1396
|
+
if options[:editor]
|
1325
1397
|
wwid.edit_last(section: options[:s], options: { search: options[:search], tag: tags, tag_bool: options[:bool] })
|
1326
1398
|
else
|
1327
1399
|
puts wwid.last(times: true, section: options[:s],
|
@@ -1380,7 +1452,7 @@ command :colors do |c|
|
|
1380
1452
|
end
|
1381
1453
|
|
1382
1454
|
desc 'Display a user-created view'
|
1383
|
-
long_desc 'Command line options override
|
1455
|
+
long_desc 'Command line options override view configuration'
|
1384
1456
|
arg_name 'VIEW_NAME'
|
1385
1457
|
command :view do |c|
|
1386
1458
|
c.desc 'Section'
|
@@ -1404,6 +1476,18 @@ command :view do |c|
|
|
1404
1476
|
c.desc 'Include colors in output'
|
1405
1477
|
c.switch [:color], default_value: true, negatable: true
|
1406
1478
|
|
1479
|
+
c.desc 'Tag filter, combine multiple tags with a comma.'
|
1480
|
+
c.arg_name 'TAG'
|
1481
|
+
c.flag [:tag]
|
1482
|
+
|
1483
|
+
c.desc 'Tag boolean (AND,OR,NOT)'
|
1484
|
+
c.arg_name 'BOOLEAN'
|
1485
|
+
c.flag %i[b bool], must_match: /(?:and|all|any|or|not|none)/i, default_value: 'OR'
|
1486
|
+
|
1487
|
+
c.desc 'Search filter, surround with slashes for regex (/query/)'
|
1488
|
+
c.arg_name 'QUERY'
|
1489
|
+
c.flag [:search]
|
1490
|
+
|
1407
1491
|
c.desc 'Sort tags by (name|time)'
|
1408
1492
|
c.arg_name 'KEY'
|
1409
1493
|
c.flag [:tag_sort], must_match: /^(?:name|time)$/i
|
@@ -1412,10 +1496,20 @@ command :view do |c|
|
|
1412
1496
|
c.arg_name 'DIRECTION'
|
1413
1497
|
c.flag [:tag_order], must_match: /^(?:a(?:sc)?|d(?:esc)?)$/i
|
1414
1498
|
|
1499
|
+
c.desc 'View entries older than date'
|
1500
|
+
c.arg_name 'DATE_STRING'
|
1501
|
+
c.flag [:before]
|
1502
|
+
|
1503
|
+
c.desc 'View entries newer than date'
|
1504
|
+
c.arg_name 'DATE_STRING'
|
1505
|
+
c.flag [:after]
|
1506
|
+
|
1415
1507
|
c.desc 'Only show items with recorded time intervals (override view settings)'
|
1416
1508
|
c.switch [:only_timed], default_value: false, negatable: false
|
1417
1509
|
|
1418
1510
|
c.action do |_global_options, options, args|
|
1511
|
+
exit_now! '--tag and --search cannot be used together' if options[:tag] && options[:search]
|
1512
|
+
|
1419
1513
|
title = if args.empty?
|
1420
1514
|
wwid.choose_view
|
1421
1515
|
else
|
@@ -1440,7 +1534,11 @@ command :view do |c|
|
|
1440
1534
|
format = view.key?('date_format') ? view['date_format'] : nil
|
1441
1535
|
tags_color = view.key?('tags_color') ? view['tags_color'] : nil
|
1442
1536
|
tag_filter = false
|
1443
|
-
if
|
1537
|
+
if options[:tag]
|
1538
|
+
tag_filter = { 'tags' => [], 'bool' => 'OR' }
|
1539
|
+
tag_filter['tags'] = options[:tag].gsub(/[, ]+/, ' ').split(' ').map(&:strip)
|
1540
|
+
tag_filter['bool'] = options[:bool].normalize_bool
|
1541
|
+
elsif view.key?('tags') && !(view['tags'].nil? || view['tags'].empty?)
|
1444
1542
|
tag_filter = { 'tags' => [], 'bool' => 'OR' }
|
1445
1543
|
tag_filter['tags'] = if view['tags'].instance_of?(Array)
|
1446
1544
|
view['tags'].map(&:strip)
|
@@ -1489,14 +1587,17 @@ command :view do |c|
|
|
1489
1587
|
else
|
1490
1588
|
'asc'
|
1491
1589
|
end
|
1492
|
-
|
1590
|
+
|
1493
1591
|
opts = {
|
1592
|
+
after: options[:after],
|
1593
|
+
before: options[:before],
|
1494
1594
|
count: count,
|
1495
1595
|
format: format,
|
1496
1596
|
highlight: options[:color],
|
1497
1597
|
only_timed: only_timed,
|
1498
1598
|
order: order,
|
1499
|
-
output: options[:
|
1599
|
+
output: options[:output],
|
1600
|
+
search: options[:search],
|
1500
1601
|
section: section,
|
1501
1602
|
sort_tags: options[:sort_tags],
|
1502
1603
|
tag_filter: tag_filter,
|
@@ -1554,6 +1655,11 @@ command :archive do |c|
|
|
1554
1655
|
c.arg_name 'QUERY'
|
1555
1656
|
c.flag [:search]
|
1556
1657
|
|
1658
|
+
c.desc 'Archive entries older than date
|
1659
|
+
(Flexible date format, e.g. 1/27/2021, 2020-07-19, or Monday 3pm)'
|
1660
|
+
c.arg_name 'DATE_STRING'
|
1661
|
+
c.flag [:before]
|
1662
|
+
|
1557
1663
|
c.action do |_global_options, options, args|
|
1558
1664
|
if args.empty?
|
1559
1665
|
section = wwid.current_section
|
@@ -1583,6 +1689,7 @@ command :archive do |c|
|
|
1583
1689
|
'AND'
|
1584
1690
|
end
|
1585
1691
|
opts = {
|
1692
|
+
before: options[:before],
|
1586
1693
|
bool: options[:bool],
|
1587
1694
|
destination: options[:to],
|
1588
1695
|
keep: options[:keep],
|
@@ -1615,6 +1722,11 @@ command :rotate do |c|
|
|
1615
1722
|
c.arg_name 'QUERY'
|
1616
1723
|
c.flag [:search]
|
1617
1724
|
|
1725
|
+
c.desc 'Rotate entries older than date
|
1726
|
+
(Flexible date format, e.g. 1/27/2021, 2020-07-19, or Monday 3pm)'
|
1727
|
+
c.arg_name 'DATE_STRING'
|
1728
|
+
c.flag [:before]
|
1729
|
+
|
1618
1730
|
c.action do |_global_options, options, args|
|
1619
1731
|
if options[:section] && options[:section] !~ /^all$/i
|
1620
1732
|
options[:section] = wwid.guess_section(options[:section])
|
@@ -1641,11 +1753,11 @@ command :open do |c|
|
|
1641
1753
|
if `uname` =~ /Darwin/
|
1642
1754
|
c.desc 'Open with app name'
|
1643
1755
|
c.arg_name 'APP_NAME'
|
1644
|
-
c.flag [
|
1756
|
+
c.flag %i[a app]
|
1645
1757
|
|
1646
1758
|
c.desc 'Open with app bundle id'
|
1647
1759
|
c.arg_name 'BUNDLE_ID'
|
1648
|
-
c.flag [
|
1760
|
+
c.flag %i[b bundle_id]
|
1649
1761
|
end
|
1650
1762
|
c.desc "Open with $EDITOR (#{ENV['EDITOR']})"
|
1651
1763
|
c.switch %i[e editor], negatable: false, default_value: false
|
@@ -1656,11 +1768,11 @@ command :open do |c|
|
|
1656
1768
|
k.instance_of?(String) || v.nil? || v == false
|
1657
1769
|
end
|
1658
1770
|
if `uname` =~ /Darwin/
|
1659
|
-
if options[:
|
1771
|
+
if options[:app]
|
1660
1772
|
system %(open -a "#{options[:a]}" "#{File.expand_path(wwid.doing_file)}")
|
1661
|
-
elsif options[:
|
1773
|
+
elsif options[:bundle_id]
|
1662
1774
|
system %(open -b "#{options[:b]}" "#{File.expand_path(wwid.doing_file)}")
|
1663
|
-
elsif options[:
|
1775
|
+
elsif options[:editor]
|
1664
1776
|
exit_now! 'No EDITOR variable defined in environment' if ENV['EDITOR'].nil?
|
1665
1777
|
|
1666
1778
|
system %($EDITOR "#{File.expand_path(wwid.doing_file)}")
|
data/lib/doing/version.rb
CHANGED
data/lib/doing/wwid.rb
CHANGED
@@ -124,7 +124,8 @@ class WWID
|
|
124
124
|
@config['templates']['recent'] ||= {
|
125
125
|
'date_format' => '%_I:%M%P',
|
126
126
|
'template' => '%shortdate: %title (%section)',
|
127
|
-
'wrap_width' => 88
|
127
|
+
'wrap_width' => 88,
|
128
|
+
'count' => 10
|
128
129
|
}
|
129
130
|
@config['views'] ||= {
|
130
131
|
'done' => {
|
@@ -1100,7 +1101,6 @@ class WWID
|
|
1100
1101
|
items = @content[section]['items'].dup.sort_by { |item| item['date'] }.reverse
|
1101
1102
|
idx = 0
|
1102
1103
|
done_date = Time.now
|
1103
|
-
next_start = Time.now
|
1104
1104
|
count = (opt[:count]).zero? ? items.length : opt[:count]
|
1105
1105
|
items.map! do |item|
|
1106
1106
|
break if idx == count
|
@@ -1119,8 +1119,8 @@ class WWID
|
|
1119
1119
|
end
|
1120
1120
|
else
|
1121
1121
|
if opt[:sequential]
|
1122
|
-
|
1123
|
-
|
1122
|
+
next_entry = next_item(item)
|
1123
|
+
done_date = next_entry['date'] - 60 if next_entry
|
1124
1124
|
elsif opt[:took]
|
1125
1125
|
if item['date'] + opt[:took] > Time.now
|
1126
1126
|
item['date'] = Time.now - opt[:took]
|
@@ -1209,6 +1209,24 @@ class WWID
|
|
1209
1209
|
return new_item
|
1210
1210
|
end
|
1211
1211
|
|
1212
|
+
##
|
1213
|
+
## @brief Get next item in the index
|
1214
|
+
##
|
1215
|
+
## @param old_item
|
1216
|
+
##
|
1217
|
+
def next_item(old_item)
|
1218
|
+
section = old_item['section']
|
1219
|
+
|
1220
|
+
section_items = @content[section]['items'].sort_by { |entry| entry['date'] }
|
1221
|
+
idx = section_items.index(old_item)
|
1222
|
+
|
1223
|
+
if section_items.size > idx
|
1224
|
+
section_items[idx + 1]
|
1225
|
+
else
|
1226
|
+
nil
|
1227
|
+
end
|
1228
|
+
end
|
1229
|
+
|
1212
1230
|
##
|
1213
1231
|
## @brief Delete an item from the index
|
1214
1232
|
##
|
@@ -1478,7 +1496,7 @@ class WWID
|
|
1478
1496
|
##
|
1479
1497
|
## @param file (String) The filepath to write to
|
1480
1498
|
##
|
1481
|
-
def write(file = nil)
|
1499
|
+
def write(file = nil, backup: true)
|
1482
1500
|
output = @other_content_top ? "#{@other_content_top.join("\n")}\n" : ''
|
1483
1501
|
|
1484
1502
|
@content.each do |title, section|
|
@@ -1490,7 +1508,7 @@ class WWID
|
|
1490
1508
|
$stdout.puts output
|
1491
1509
|
else
|
1492
1510
|
file = File.expand_path(file)
|
1493
|
-
if File.exist?(file)
|
1511
|
+
if File.exist?(file) && backup
|
1494
1512
|
# Create a backup copy for the undo command
|
1495
1513
|
FileUtils.cp(file, "#{file}~")
|
1496
1514
|
end
|
@@ -1549,9 +1567,15 @@ class WWID
|
|
1549
1567
|
new_content[section]['items'] = []
|
1550
1568
|
|
1551
1569
|
moved_items = []
|
1552
|
-
if !tags.empty? || opt[:search]
|
1570
|
+
if !tags.empty? || opt[:search] || opt[:before]
|
1571
|
+
if opt[:before]
|
1572
|
+
time_string = opt[:before]
|
1573
|
+
time_string += ' 12am' if time_string !~ /(\d+:\d+|\d+[ap])/
|
1574
|
+
cutoff = chronify(time_string)
|
1575
|
+
end
|
1576
|
+
|
1553
1577
|
items.delete_if do |item|
|
1554
|
-
if ((!tags.empty? && item.has_tags?(tags, bool)) || (opt[:search] && item.matches_search?(opt[:search].to_s)))
|
1578
|
+
if ((!tags.empty? && item.has_tags?(tags, bool)) || (opt[:search] && item.matches_search?(opt[:search].to_s)) || (opt[:before] && item['date'] < cutoff))
|
1555
1579
|
moved_items.push(item)
|
1556
1580
|
counter += 1
|
1557
1581
|
true
|
@@ -1587,10 +1611,15 @@ class WWID
|
|
1587
1611
|
|
1588
1612
|
write(@doing_file)
|
1589
1613
|
|
1590
|
-
file = @doing_file.sub(/(\.\w+)$/, "_#{Time.now.strftime('%Y-%m-%d
|
1591
|
-
|
1614
|
+
file = @doing_file.sub(/(\.\w+)$/, "_#{Time.now.strftime('%Y-%m-%d')}\\1")
|
1615
|
+
if File.exist?(file)
|
1616
|
+
init_doing_file(file)
|
1617
|
+
@content.deep_merge(new_content)
|
1618
|
+
else
|
1619
|
+
@content = new_content
|
1620
|
+
end
|
1592
1621
|
|
1593
|
-
write(file)
|
1622
|
+
write(file, backup: false)
|
1594
1623
|
end
|
1595
1624
|
|
1596
1625
|
##
|
@@ -1713,6 +1742,24 @@ class WWID
|
|
1713
1742
|
end
|
1714
1743
|
end
|
1715
1744
|
|
1745
|
+
if opt[:before]
|
1746
|
+
time_string = opt[:before]
|
1747
|
+
time_string += ' 12am' if time_string !~ /(\d+:\d+|\d+[ap])/
|
1748
|
+
cutoff = chronify(time_string)
|
1749
|
+
if cutoff
|
1750
|
+
items.delete_if { |item| item['date'] >= cutoff }
|
1751
|
+
end
|
1752
|
+
end
|
1753
|
+
|
1754
|
+
if opt[:after]
|
1755
|
+
time_string = opt[:after]
|
1756
|
+
time_string += ' 11:59pm' if time_string !~ /(\d+:\d+|\d+[ap])/
|
1757
|
+
cutoff = chronify(time_string)
|
1758
|
+
if cutoff
|
1759
|
+
items.delete_if { |item| item['date'] <= cutoff }
|
1760
|
+
end
|
1761
|
+
end
|
1762
|
+
|
1716
1763
|
if opt[:today]
|
1717
1764
|
items.delete_if do |item|
|
1718
1765
|
item['date'] < Date.today.to_time
|
@@ -1940,13 +1987,13 @@ class WWID
|
|
1940
1987
|
|
1941
1988
|
output.sub!(/%shortdate/) do
|
1942
1989
|
if item['date'] > Date.today.to_time
|
1943
|
-
item['date'].strftime('%_I:%M%P')
|
1944
|
-
elsif item['date'] > (Date.today -
|
1945
|
-
item['date'].strftime('%a
|
1990
|
+
item['date'].strftime(' %_I:%M%P')
|
1991
|
+
elsif item['date'] > (Date.today - 6).to_time
|
1992
|
+
item['date'].strftime('%a %_I:%M%P')
|
1946
1993
|
elsif item['date'].year == Date.today.year
|
1947
|
-
item['date'].strftime('%
|
1994
|
+
item['date'].strftime('%m/%d %_I:%M%P')
|
1948
1995
|
else
|
1949
|
-
item['date'].strftime('%
|
1996
|
+
item['date'].strftime('%m/%d/%Y %_I:%M%P')
|
1950
1997
|
end
|
1951
1998
|
end
|
1952
1999
|
|
@@ -2012,7 +2059,7 @@ class WWID
|
|
2012
2059
|
destination = guess_section(destination)
|
2013
2060
|
|
2014
2061
|
if sections.include?(destination) && (sections.include?(section) || archive_all)
|
2015
|
-
do_archive(section, destination, { count: count, tags: tags, bool: bool, search: options[:search], label: options[:label] })
|
2062
|
+
do_archive(section, destination, { count: count, tags: tags, bool: bool, search: options[:search], label: options[:label], before: options[:before] })
|
2016
2063
|
write(doing_file)
|
2017
2064
|
else
|
2018
2065
|
exit_now! 'Either source or destination does not exist'
|
@@ -2045,9 +2092,15 @@ class WWID
|
|
2045
2092
|
items = @content[section]['items'].dup
|
2046
2093
|
|
2047
2094
|
moved_items = []
|
2048
|
-
if !tags.empty? || opt[:search]
|
2095
|
+
if !tags.empty? || opt[:search] || opt[:before]
|
2096
|
+
if opt[:before]
|
2097
|
+
time_string = opt[:before]
|
2098
|
+
time_string += ' 12am' if time_string !~ /(\d+:\d+|\d+[ap])/
|
2099
|
+
cutoff = chronify(time_string)
|
2100
|
+
end
|
2101
|
+
|
2049
2102
|
items.delete_if do |item|
|
2050
|
-
if (!tags.empty? && item.has_tags?(tags, bool) || (opt[:search] && item.matches_search?(opt[:search].to_s)))
|
2103
|
+
if ((!tags.empty? && item.has_tags?(tags, bool)) || (opt[:search] && item.matches_search?(opt[:search].to_s)) || (opt[:before] && item['date'] < cutoff))
|
2051
2104
|
moved_items.push(item)
|
2052
2105
|
counter += 1
|
2053
2106
|
true
|
@@ -2154,8 +2207,22 @@ class WWID
|
|
2154
2207
|
opt[:sort_tags] ||= false
|
2155
2208
|
|
2156
2209
|
cfg = @config['templates']['today']
|
2157
|
-
|
2158
|
-
|
2210
|
+
options = {
|
2211
|
+
after: opt[:after],
|
2212
|
+
before: opt[:before],
|
2213
|
+
count: 0,
|
2214
|
+
format: cfg['date_format'],
|
2215
|
+
order: 'asc',
|
2216
|
+
output: output,
|
2217
|
+
section: opt[:section],
|
2218
|
+
sort_tags: opt[:sort_tags],
|
2219
|
+
template: cfg['template'],
|
2220
|
+
times: times,
|
2221
|
+
today: true,
|
2222
|
+
totals: opt[:totals],
|
2223
|
+
wrap_width: cfg['wrap_width']
|
2224
|
+
}
|
2225
|
+
list_section(options)
|
2159
2226
|
end
|
2160
2227
|
|
2161
2228
|
##
|
@@ -2190,8 +2257,25 @@ class WWID
|
|
2190
2257
|
opt[:totals] ||= false
|
2191
2258
|
opt[:sort_tags] ||= false
|
2192
2259
|
section = guess_section(section)
|
2193
|
-
|
2194
|
-
|
2260
|
+
y = (Time.now - (60 * 60 * 24)).strftime('%Y-%m-%d')
|
2261
|
+
opt[:after] = "#{y} #{opt[:after]}" if opt[:after]
|
2262
|
+
opt[:before] = "#{y} #{opt[:before]}" if opt[:before]
|
2263
|
+
|
2264
|
+
options = {
|
2265
|
+
after: opt[:after],
|
2266
|
+
before: opt[:before],
|
2267
|
+
count: 0,
|
2268
|
+
order: 'asc',
|
2269
|
+
output: output,
|
2270
|
+
section: section,
|
2271
|
+
sort_tags: opt[:sort_tags],
|
2272
|
+
tag_order: opt[:tag_order],
|
2273
|
+
times: times,
|
2274
|
+
totals: opt[:totals],
|
2275
|
+
yesterday: true
|
2276
|
+
}
|
2277
|
+
|
2278
|
+
list_section(options)
|
2195
2279
|
end
|
2196
2280
|
|
2197
2281
|
##
|