doing 2.0.7.pre → 2.0.8.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/bin/doing +173 -6
- data/doing.rdoc +147 -2
- data/lib/doing/errors.rb +1 -1
- data/lib/doing/item.rb +12 -11
- data/lib/doing/plugins/import/calendar_import.rb +7 -1
- data/lib/doing/plugins/import/doing_import.rb +6 -6
- data/lib/doing/plugins/import/timing_import.rb +7 -1
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +27 -5
- data/lib/examples/plugins/{templates → wiki_export/templates}/wiki.css +0 -0
- data/lib/examples/plugins/{templates → wiki_export/templates}/wiki.haml +0 -0
- data/lib/examples/plugins/{templates → wiki_export/templates}/wiki_index.haml +0 -0
- data/lib/examples/plugins/{wiki_export.rb → wiki_export/wiki_export.rb} +0 -0
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 395218e7fd0178eb8d626e58c6b4ec078ff2631506829f98e7a41daacc7dd9bc
|
4
|
+
data.tar.gz: c7bda7d2e832b3f657f409c512f16bf71b8d0b247b776c4f3ce467c399482241
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73d7cfcafe737b446a6fec46a8bb8ae41503137240546cd361b1f6f292ecbf6a37c361a4708aeb9a4efcfddf76e42515e580a6c03b86c5512082e90e2bd8b325
|
7
|
+
data.tar.gz: 4f5ccc666a48629fe674923dfece11a872b59b5af7329f7484c777b4cc6166bebb287df5f19ea2d802212e553d03a2ac4b853f31c1f41f4204b6293838cd2695
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
### 2.0.8.pre
|
2
|
+
|
3
|
+
#### NEW
|
4
|
+
|
5
|
+
- Add `--exact` flag to all commands with `--search` flag to force exact matching without requiring single quote prefix
|
6
|
+
- Add `--not` flag to all commands with filters (--tag, --search, --before, etc.) to negate the filter and return entries NOT matched
|
7
|
+
|
1
8
|
### 2.0.7.pre
|
2
9
|
|
3
10
|
#### FIXED
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -6,7 +6,7 @@ _If you're one of the rare people like me who find this useful, feel free to [bu
|
|
6
6
|
|
7
7
|
<!--README-->
|
8
8
|
|
9
|
-
The current version of `doing` is <!--VER-->2.0.
|
9
|
+
The current version of `doing` is <!--VER-->2.0.7<!--END VER-->.
|
10
10
|
|
11
11
|
Find all of the documentation in the [doing wiki](https://github.com/ttscoff/doing/wiki).
|
12
12
|
|
data/bin/doing
CHANGED
@@ -180,7 +180,7 @@ end
|
|
180
180
|
|
181
181
|
desc 'Reset the start time of an entry'
|
182
182
|
command %i[reset begin] do |c|
|
183
|
-
c.desc '
|
183
|
+
c.desc 'Limit search to section'
|
184
184
|
c.arg_name 'NAME'
|
185
185
|
c.flag %i[s section], default_value: 'All'
|
186
186
|
|
@@ -195,6 +195,12 @@ command %i[reset begin] do |c|
|
|
195
195
|
c.arg_name 'QUERY'
|
196
196
|
c.flag [:search]
|
197
197
|
|
198
|
+
c.desc 'Force exact search string matching (case sensitive)'
|
199
|
+
c.switch %i[x exact], default_value: false, negatable: false
|
200
|
+
|
201
|
+
c.desc 'Reset items that *don\'t* match search/tag filters'
|
202
|
+
c.switch [:not], default_value: false, negatable: false
|
203
|
+
|
198
204
|
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
|
199
205
|
c.arg_name 'BOOLEAN'
|
200
206
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
|
@@ -209,6 +215,13 @@ command %i[reset begin] do |c|
|
|
209
215
|
|
210
216
|
options[:tag_bool] = options[:bool].normalize_bool
|
211
217
|
|
218
|
+
if options[:search]
|
219
|
+
search = options[:search]
|
220
|
+
search.sub!(/^'?/, "'") if options[:exact]
|
221
|
+
options[:search] = search
|
222
|
+
end
|
223
|
+
|
224
|
+
|
212
225
|
items = wwid.filter_items([], opt: options)
|
213
226
|
|
214
227
|
if options[:interactive]
|
@@ -266,6 +279,12 @@ command :note do |c|
|
|
266
279
|
c.arg_name 'QUERY'
|
267
280
|
c.flag [:search]
|
268
281
|
|
282
|
+
c.desc 'Force exact search string matching (case sensitive)'
|
283
|
+
c.switch %i[x exact], default_value: false, negatable: false
|
284
|
+
|
285
|
+
c.desc 'Add note to item that *doesn\'t* match search/tag filters'
|
286
|
+
c.switch [:not], default_value: false, negatable: false
|
287
|
+
|
269
288
|
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
|
270
289
|
c.arg_name 'BOOLEAN'
|
271
290
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
|
@@ -280,6 +299,13 @@ command :note do |c|
|
|
280
299
|
|
281
300
|
options[:tag_bool] = options[:bool].normalize_bool
|
282
301
|
|
302
|
+
if options[:search]
|
303
|
+
search = options[:search]
|
304
|
+
search.sub!(/^'?/, "'") if options[:exact]
|
305
|
+
options[:search] = search
|
306
|
+
end
|
307
|
+
|
308
|
+
|
283
309
|
last_entry = wwid.last_entry(options)
|
284
310
|
|
285
311
|
unless last_entry
|
@@ -473,6 +499,12 @@ command :select do |c|
|
|
473
499
|
c.arg_name 'QUERY'
|
474
500
|
c.flag %i[q query search]
|
475
501
|
|
502
|
+
c.desc 'Force exact search string matching (case sensitive)'
|
503
|
+
c.switch %i[x exact], default_value: false, negatable: false
|
504
|
+
|
505
|
+
c.desc 'Select items that *don\'t* match search/tag filters'
|
506
|
+
c.switch [:not], default_value: false, negatable: false
|
507
|
+
|
476
508
|
c.desc 'Use --no-menu to skip the interactive menu. Use with --query to filter items and act on results automatically. Test with `--output doing` to preview matches.'
|
477
509
|
c.switch %i[menu], negatable: true, default_value: true
|
478
510
|
|
@@ -844,6 +876,12 @@ command :finish do |c|
|
|
844
876
|
c.arg_name 'QUERY'
|
845
877
|
c.flag [:search]
|
846
878
|
|
879
|
+
c.desc 'Force exact search string matching (case sensitive)'
|
880
|
+
c.switch %i[x exact], default_value: false, negatable: false
|
881
|
+
|
882
|
+
c.desc 'Finish items that *don\'t* match search/tag filters'
|
883
|
+
c.switch [:not], default_value: false, negatable: false
|
884
|
+
|
847
885
|
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
|
848
886
|
c.arg_name 'BOOLEAN'
|
849
887
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
|
@@ -912,12 +950,20 @@ command :finish do |c|
|
|
912
950
|
count = args[0] ? args[0].to_i : 1
|
913
951
|
end
|
914
952
|
|
953
|
+
search = nil
|
954
|
+
|
955
|
+
if options[:search]
|
956
|
+
search = options[:search]
|
957
|
+
search.sub!(/^'?/, "'") if options[:exact]
|
958
|
+
end
|
959
|
+
|
915
960
|
opts = {
|
916
961
|
archive: options[:archive],
|
917
962
|
back: date,
|
918
963
|
count: count,
|
919
964
|
date: options[:date],
|
920
|
-
search:
|
965
|
+
search: search,
|
966
|
+
not: options[:not],
|
921
967
|
section: options[:section],
|
922
968
|
sequential: options[:auto],
|
923
969
|
tag: tags,
|
@@ -951,6 +997,12 @@ command %i[again resume] do |c|
|
|
951
997
|
c.arg_name 'QUERY'
|
952
998
|
c.flag [:search]
|
953
999
|
|
1000
|
+
c.desc 'Force exact search string matching (case sensitive)'
|
1001
|
+
c.switch %i[x exact], default_value: false, negatable: false
|
1002
|
+
|
1003
|
+
c.desc 'Resume items that *don\'t* match search/tag filters'
|
1004
|
+
c.switch [:not], default_value: false, negatable: false
|
1005
|
+
|
954
1006
|
c.desc 'Boolean used to combine multiple tags'
|
955
1007
|
c.arg_name 'BOOLEAN'
|
956
1008
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
|
@@ -967,7 +1019,15 @@ command %i[again resume] do |c|
|
|
967
1019
|
|
968
1020
|
c.action do |_global_options, options, _args|
|
969
1021
|
tags = options[:tag].nil? ? [] : options[:tag].to_tags
|
1022
|
+
|
1023
|
+
if options[:search]
|
1024
|
+
search = options[:search]
|
1025
|
+
search.sub!(/^'?/, "'") if options[:exact]
|
1026
|
+
options[:search] = search
|
1027
|
+
end
|
1028
|
+
|
970
1029
|
opts = options
|
1030
|
+
|
971
1031
|
opts[:tag] = tags
|
972
1032
|
opts[:tag_bool] = options[:bool].normalize_bool
|
973
1033
|
opts[:interactive] = options[:interactive]
|
@@ -1037,6 +1097,12 @@ command :tag do |c|
|
|
1037
1097
|
c.arg_name 'QUERY'
|
1038
1098
|
c.flag [:search]
|
1039
1099
|
|
1100
|
+
c.desc 'Force exact search string matching (case sensitive)'
|
1101
|
+
c.switch %i[x exact], default_value: false, negatable: false
|
1102
|
+
|
1103
|
+
c.desc 'Tag items that *don\'t* match search/tag filters'
|
1104
|
+
c.switch [:not], default_value: false, negatable: false
|
1105
|
+
|
1040
1106
|
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
|
1041
1107
|
c.arg_name 'BOOLEAN'
|
1042
1108
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
|
@@ -1081,6 +1147,11 @@ command :tag do |c|
|
|
1081
1147
|
count = options[:count].to_i
|
1082
1148
|
end
|
1083
1149
|
|
1150
|
+
if options[:search]
|
1151
|
+
search = options[:search]
|
1152
|
+
search.sub!(/^'?/, "'") if options[:exact]
|
1153
|
+
options[:search] = search
|
1154
|
+
end
|
1084
1155
|
|
1085
1156
|
if count.zero? && !options[:force]
|
1086
1157
|
if options[:search]
|
@@ -1104,7 +1175,7 @@ command :tag do |c|
|
|
1104
1175
|
|
1105
1176
|
res = wwid.yn(question, default_response: false)
|
1106
1177
|
|
1107
|
-
|
1178
|
+
raise UserCancelled unless res
|
1108
1179
|
end
|
1109
1180
|
|
1110
1181
|
options[:count] = count
|
@@ -1152,6 +1223,12 @@ command [:mark, :flag] do |c|
|
|
1152
1223
|
c.arg_name 'QUERY'
|
1153
1224
|
c.flag [:search]
|
1154
1225
|
|
1226
|
+
c.desc 'Force exact search string matching (case sensitive)'
|
1227
|
+
c.switch %i[x exact], default_value: false, negatable: false
|
1228
|
+
|
1229
|
+
c.desc 'Flag items that *don\'t* match search/tag/date filters'
|
1230
|
+
c.switch [:not], default_value: false, negatable: false
|
1231
|
+
|
1155
1232
|
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
|
1156
1233
|
c.arg_name 'BOOLEAN'
|
1157
1234
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
|
@@ -1183,6 +1260,12 @@ command [:mark, :flag] do |c|
|
|
1183
1260
|
count = options[:count].to_i
|
1184
1261
|
end
|
1185
1262
|
|
1263
|
+
if options[:search]
|
1264
|
+
search = options[:search]
|
1265
|
+
search.sub!(/^'?/, "'") if options[:exact]
|
1266
|
+
options[:search] = search
|
1267
|
+
end
|
1268
|
+
|
1186
1269
|
if count.zero? && !options[:force]
|
1187
1270
|
if options[:search]
|
1188
1271
|
section_q = ' matching your search terms'
|
@@ -1257,6 +1340,12 @@ command :show do |c|
|
|
1257
1340
|
c.arg_name 'QUERY'
|
1258
1341
|
c.flag [:search]
|
1259
1342
|
|
1343
|
+
c.desc 'Force exact search string matching (case sensitive)'
|
1344
|
+
c.switch %i[x exact], default_value: false, negatable: false
|
1345
|
+
|
1346
|
+
c.desc 'Show items that *don\'t* match search/tag/date filters'
|
1347
|
+
c.switch [:not], default_value: false, negatable: false
|
1348
|
+
|
1260
1349
|
c.desc 'Sort order (asc/desc)'
|
1261
1350
|
c.arg_name 'ORDER'
|
1262
1351
|
c.flag %i[s sort], must_match: REGEX_SORT_ORDER, default_value: 'asc'
|
@@ -1361,6 +1450,12 @@ command :show do |c|
|
|
1361
1450
|
|
1362
1451
|
tags_color = settings.key?('tags_color') ? settings['tags_color'] : nil
|
1363
1452
|
|
1453
|
+
if options[:search]
|
1454
|
+
search = options[:search]
|
1455
|
+
search.sub!(/^'?/, "'") if options[:exact]
|
1456
|
+
options[:search] = search
|
1457
|
+
end
|
1458
|
+
|
1364
1459
|
opt = options.dup
|
1365
1460
|
|
1366
1461
|
opt[:sort_tags] = options[:tag_sort] =~ /^n/i
|
@@ -1423,6 +1518,15 @@ command %i[grep search] do |c|
|
|
1423
1518
|
c.desc 'Only show items with recorded time intervals'
|
1424
1519
|
c.switch [:only_timed], default_value: false, negatable: false
|
1425
1520
|
|
1521
|
+
c.desc 'Force exact string matching (case sensitive)'
|
1522
|
+
c.switch %i[x exact], default_value: false, negatable: false
|
1523
|
+
|
1524
|
+
c.desc 'Force case sensitive matching'
|
1525
|
+
c.switch %i[case]
|
1526
|
+
|
1527
|
+
c.desc 'Show items that *don\'t* match search string'
|
1528
|
+
c.switch [:not], default_value: false, negatable: false
|
1529
|
+
|
1426
1530
|
c.desc 'Display an interactive menu of results to perform further operations'
|
1427
1531
|
c.switch %i[i interactive], default_value: false, negatable: false
|
1428
1532
|
|
@@ -1432,11 +1536,13 @@ command %i[grep search] do |c|
|
|
1432
1536
|
tags_color = settings.key?('tags_color') ? settings['tags_color'] : nil
|
1433
1537
|
|
1434
1538
|
section = wwid.guess_section(options[:section]) if options[:section]
|
1539
|
+
search = args.join(' ')
|
1540
|
+
search.sub!(/^'?/, "'") if options[:exact]
|
1435
1541
|
|
1436
1542
|
options[:times] = true if options[:totals]
|
1437
1543
|
options[:sort_tags] = options[:tag_sort] =~ /^n/i
|
1438
1544
|
options[:highlight] = true
|
1439
|
-
options[:search] =
|
1545
|
+
options[:search] = search
|
1440
1546
|
options[:section] = section
|
1441
1547
|
options[:tags_color] = tags_color
|
1442
1548
|
|
@@ -1754,6 +1860,12 @@ command :last do |c|
|
|
1754
1860
|
c.arg_name 'QUERY'
|
1755
1861
|
c.flag [:search]
|
1756
1862
|
|
1863
|
+
c.desc 'Force exact search string matching (case sensitive)'
|
1864
|
+
c.switch %i[x exact], default_value: false, negatable: false
|
1865
|
+
|
1866
|
+
c.desc 'Show items that *don\'t* match search string or tag filter'
|
1867
|
+
c.switch [:not], default_value: false, negatable: false
|
1868
|
+
|
1757
1869
|
c.action do |global_options, options, _args|
|
1758
1870
|
raise InvalidArgument, '--tag and --search can not be used together' if options[:tag] && options[:search]
|
1759
1871
|
|
@@ -1772,11 +1884,18 @@ command :last do |c|
|
|
1772
1884
|
|
1773
1885
|
end
|
1774
1886
|
|
1887
|
+
search = nil
|
1888
|
+
|
1889
|
+
if options[:search]
|
1890
|
+
search = options[:search]
|
1891
|
+
search.sub!(/^'?/, "'") if options[:exact]
|
1892
|
+
end
|
1893
|
+
|
1775
1894
|
if options[:editor]
|
1776
|
-
wwid.edit_last(section: options[:s], options: { search:
|
1895
|
+
wwid.edit_last(section: options[:s], options: { search: search, tag: tags, tag_bool: options[:bool], not: options[:not] })
|
1777
1896
|
else
|
1778
1897
|
Doing::Pager::page wwid.last(times: true, section: options[:s],
|
1779
|
-
options: { search: options[:
|
1898
|
+
options: { search: search, negate: options[:not], tag: tags, tag_bool: options[:bool] }).strip
|
1780
1899
|
end
|
1781
1900
|
end
|
1782
1901
|
end
|
@@ -1934,6 +2053,12 @@ command :view do |c|
|
|
1934
2053
|
c.arg_name 'QUERY'
|
1935
2054
|
c.flag [:search]
|
1936
2055
|
|
2056
|
+
c.desc 'Force exact search string matching (case sensitive)'
|
2057
|
+
c.switch %i[x exact], default_value: false, negatable: false
|
2058
|
+
|
2059
|
+
c.desc 'Show items that *don\'t* match search string'
|
2060
|
+
c.switch [:not], default_value: false, negatable: false
|
2061
|
+
|
1937
2062
|
c.desc 'Sort tags by (name|time)'
|
1938
2063
|
c.arg_name 'KEY'
|
1939
2064
|
c.flag [:tag_sort], must_match: /^(?:name|time)$/i
|
@@ -2065,7 +2190,15 @@ command :view do |c|
|
|
2065
2190
|
dates = [start, finish]
|
2066
2191
|
end
|
2067
2192
|
|
2193
|
+
search = nil
|
2194
|
+
|
2195
|
+
if options[:search]
|
2196
|
+
search = options[:search]
|
2197
|
+
search.sub!(/^'?/, "'") if options[:exact]
|
2198
|
+
end
|
2199
|
+
|
2068
2200
|
opts = options
|
2201
|
+
opts[:search] = search
|
2069
2202
|
opts[:output] = output_format
|
2070
2203
|
opts[:count] = count
|
2071
2204
|
opts[:format] = date_format
|
@@ -2138,6 +2271,12 @@ command %i[archive move] do |c|
|
|
2138
2271
|
c.arg_name 'QUERY'
|
2139
2272
|
c.flag [:search]
|
2140
2273
|
|
2274
|
+
c.desc 'Force exact search string matching (case sensitive)'
|
2275
|
+
c.switch %i[x exact], default_value: false, negatable: false
|
2276
|
+
|
2277
|
+
c.desc 'Show items that *don\'t* match search string'
|
2278
|
+
c.switch [:not], default_value: false, negatable: false
|
2279
|
+
|
2141
2280
|
c.desc 'Archive entries older than date
|
2142
2281
|
(Flexible date format, e.g. 1/27/2021, 2020-07-19, or Monday 3pm)'
|
2143
2282
|
c.arg_name 'DATE_STRING'
|
@@ -2161,7 +2300,15 @@ command %i[archive move] do |c|
|
|
2161
2300
|
|
2162
2301
|
tags.concat(options[:tag].to_tags) if options[:tag]
|
2163
2302
|
|
2303
|
+
search = nil
|
2304
|
+
|
2305
|
+
if options[:search]
|
2306
|
+
search = options[:search]
|
2307
|
+
search.sub!(/^'?/, "'") if options[:exact]
|
2308
|
+
end
|
2309
|
+
|
2164
2310
|
opts = options
|
2311
|
+
opts[:search] = search
|
2165
2312
|
opts[:bool] = options[:bool].normalize_bool
|
2166
2313
|
opts[:destination] = options[:to]
|
2167
2314
|
opts[:tags] = tags
|
@@ -2196,6 +2343,12 @@ command :rotate do |c|
|
|
2196
2343
|
c.arg_name 'QUERY'
|
2197
2344
|
c.flag [:search]
|
2198
2345
|
|
2346
|
+
c.desc 'Force exact search string matching (case sensitive)'
|
2347
|
+
c.switch %i[x exact], default_value: false, negatable: false
|
2348
|
+
|
2349
|
+
c.desc 'Rotate items that *don\'t* match search string or tag filter'
|
2350
|
+
c.switch [:not], default_value: false, negatable: false
|
2351
|
+
|
2199
2352
|
c.desc 'Rotate entries older than date
|
2200
2353
|
(Flexible date format, e.g. 1/27/2021, 2020-07-19, or Monday 3pm)'
|
2201
2354
|
c.arg_name 'DATE_STRING'
|
@@ -2208,6 +2361,14 @@ command :rotate do |c|
|
|
2208
2361
|
|
2209
2362
|
options[:bool] = options[:bool].normalize_bool
|
2210
2363
|
|
2364
|
+
search = nil
|
2365
|
+
|
2366
|
+
if options[:search]
|
2367
|
+
search = options[:search]
|
2368
|
+
search.sub!(/^'?/, "'") if options[:exact]
|
2369
|
+
options[:search] = search
|
2370
|
+
end
|
2371
|
+
|
2211
2372
|
wwid.rotate(options)
|
2212
2373
|
end
|
2213
2374
|
end
|
@@ -2396,6 +2557,12 @@ command :import do |c|
|
|
2396
2557
|
c.arg_name 'QUERY'
|
2397
2558
|
c.flag [:search]
|
2398
2559
|
|
2560
|
+
c.desc 'Force exact search string matching (case sensitive)'
|
2561
|
+
c.switch %i[x exact], default_value: false, negatable: false
|
2562
|
+
|
2563
|
+
c.desc 'Import items that *don\'t* match search/tag/date filters'
|
2564
|
+
c.switch [:not], default_value: false, negatable: false
|
2565
|
+
|
2399
2566
|
c.desc 'Only import items with recorded time intervals'
|
2400
2567
|
c.switch [:only_timed], default_value: false, negatable: false
|
2401
2568
|
|
data/doing.rdoc
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Doing uses a TaskPaper-like formatting to keep a plain text record of what you've been doing, complete with tag-based time tracking. The command line tool allows you to add entries, annotate with tags and notes, and view your entries with myriad options, with a focus on a "natural" language syntax.
|
4
4
|
|
5
|
-
v2.0.
|
5
|
+
v2.0.8.pre
|
6
6
|
|
7
7
|
=== Global Options
|
8
8
|
=== --config_file arg
|
@@ -133,6 +133,16 @@ Select item to resume from a menu of matching entries
|
|
133
133
|
|
134
134
|
|
135
135
|
|
136
|
+
===== --not
|
137
|
+
Resume items that *don't* match search/tag filters
|
138
|
+
|
139
|
+
|
140
|
+
|
141
|
+
===== -x|--exact
|
142
|
+
Force exact search string matching (case sensitive)
|
143
|
+
|
144
|
+
|
145
|
+
|
136
146
|
==== Command: <tt>archive|move SECTION_OR_TAG</tt>
|
137
147
|
Move entries between sections
|
138
148
|
|
@@ -191,6 +201,16 @@ Label moved items with @from(SECTION_NAME)
|
|
191
201
|
|
192
202
|
|
193
203
|
|
204
|
+
===== --not
|
205
|
+
Show items that *don't* match search string
|
206
|
+
|
207
|
+
|
208
|
+
|
209
|
+
===== -x|--exact
|
210
|
+
Force exact search string matching (case sensitive)
|
211
|
+
|
212
|
+
|
213
|
+
|
194
214
|
==== Command: <tt>autotag </tt>
|
195
215
|
Autotag last entry or filtered entries
|
196
216
|
|
@@ -524,6 +544,11 @@ Select item(s) to finish from a menu of matching entries
|
|
524
544
|
|
525
545
|
|
526
546
|
|
547
|
+
===== --not
|
548
|
+
Finish items that *don't* match search/tag filters
|
549
|
+
|
550
|
+
|
551
|
+
|
527
552
|
===== -r|--remove
|
528
553
|
Remove done tag
|
529
554
|
|
@@ -534,6 +559,11 @@ Finish last entry (or entries) not already marked @done
|
|
534
559
|
|
535
560
|
|
536
561
|
|
562
|
+
===== -x|--exact
|
563
|
+
Force exact search string matching (case sensitive)
|
564
|
+
|
565
|
+
|
566
|
+
|
537
567
|
==== Command: <tt>grep|search SEARCH_PATTERN</tt>
|
538
568
|
Search for entries
|
539
569
|
|
@@ -577,11 +607,21 @@ Sort tags by (name|time)
|
|
577
607
|
[Must Match] (?i-mx:^(?:name|time)$)
|
578
608
|
|
579
609
|
|
610
|
+
===== --[no-]case
|
611
|
+
Force case sensitive matching
|
612
|
+
|
613
|
+
|
614
|
+
|
580
615
|
===== -i|--interactive
|
581
616
|
Display an interactive menu of results to perform further operations
|
582
617
|
|
583
618
|
|
584
619
|
|
620
|
+
===== --not
|
621
|
+
Show items that *don't* match search string
|
622
|
+
|
623
|
+
|
624
|
+
|
585
625
|
===== --only_timed
|
586
626
|
Only show items with recorded time intervals
|
587
627
|
|
@@ -597,6 +637,11 @@ Show intervals with totals at the end of output
|
|
597
637
|
|
598
638
|
|
599
639
|
|
640
|
+
===== -x|--exact
|
641
|
+
Force exact string matching (case sensitive)
|
642
|
+
|
643
|
+
|
644
|
+
|
600
645
|
==== Command: <tt>help command</tt>
|
601
646
|
Shows a list of commands or help for one command
|
602
647
|
|
@@ -675,6 +720,11 @@ Autotag entries
|
|
675
720
|
|
676
721
|
|
677
722
|
|
723
|
+
===== --not
|
724
|
+
Import items that *don't* match search/tag/date filters
|
725
|
+
|
726
|
+
|
727
|
+
|
678
728
|
===== --only_timed
|
679
729
|
Only import items with recorded time intervals
|
680
730
|
|
@@ -685,6 +735,11 @@ Allow entries that overlap existing times
|
|
685
735
|
|
686
736
|
|
687
737
|
|
738
|
+
===== -x|--exact
|
739
|
+
Force exact search string matching (case sensitive)
|
740
|
+
|
741
|
+
|
742
|
+
|
688
743
|
==== Command: <tt>last </tt>
|
689
744
|
Show the last entry, optionally edit
|
690
745
|
|
@@ -724,6 +779,16 @@ Edit entry with vim
|
|
724
779
|
|
725
780
|
|
726
781
|
|
782
|
+
===== --not
|
783
|
+
Show items that *don't* match search string or tag filter
|
784
|
+
|
785
|
+
|
786
|
+
|
787
|
+
===== -x|--exact
|
788
|
+
Force exact search string matching (case sensitive)
|
789
|
+
|
790
|
+
|
791
|
+
|
727
792
|
==== Command: <tt>later ENTRY</tt>
|
728
793
|
Add an item to the Later section
|
729
794
|
|
@@ -806,6 +871,11 @@ Select item(s) to flag from a menu of matching entries
|
|
806
871
|
|
807
872
|
|
808
873
|
|
874
|
+
===== --not
|
875
|
+
Flag items that *don't* match search/tag/date filters
|
876
|
+
|
877
|
+
|
878
|
+
|
809
879
|
===== -r|--remove
|
810
880
|
Remove flag
|
811
881
|
|
@@ -816,6 +886,11 @@ Flag last entry (or entries) not marked @done
|
|
816
886
|
|
817
887
|
|
818
888
|
|
889
|
+
===== -x|--exact
|
890
|
+
Force exact search string matching (case sensitive)
|
891
|
+
|
892
|
+
|
893
|
+
|
819
894
|
==== Command: <tt>meanwhile ENTRY</tt>
|
820
895
|
Finish any running @meanwhile tasks and optionally create a new one
|
821
896
|
|
@@ -900,11 +975,21 @@ Select item for new note from a menu of matching entries
|
|
900
975
|
|
901
976
|
|
902
977
|
|
978
|
+
===== --not
|
979
|
+
Add note to item that *doesn't* match search/tag filters
|
980
|
+
|
981
|
+
|
982
|
+
|
903
983
|
===== -r|--remove
|
904
984
|
Replace/Remove last entry's note (default append)
|
905
985
|
|
906
986
|
|
907
987
|
|
988
|
+
===== -x|--exact
|
989
|
+
Force exact search string matching (case sensitive)
|
990
|
+
|
991
|
+
|
992
|
+
|
908
993
|
==== Command: <tt>now|next ENTRY</tt>
|
909
994
|
Add an entry
|
910
995
|
|
@@ -1075,7 +1160,7 @@ Boolean (AND|OR|NOT) with which to combine multiple tag filters
|
|
1075
1160
|
|
1076
1161
|
===== -s|--section NAME
|
1077
1162
|
|
1078
|
-
|
1163
|
+
Limit search to section
|
1079
1164
|
|
1080
1165
|
[Default Value] All
|
1081
1166
|
|
@@ -1099,11 +1184,21 @@ Select from a menu of matching entries
|
|
1099
1184
|
|
1100
1185
|
|
1101
1186
|
|
1187
|
+
===== --not
|
1188
|
+
Reset items that *don't* match search/tag filters
|
1189
|
+
|
1190
|
+
|
1191
|
+
|
1102
1192
|
===== -r|--[no-]resume
|
1103
1193
|
Resume entry (remove @done)
|
1104
1194
|
|
1105
1195
|
|
1106
1196
|
|
1197
|
+
===== -x|--exact
|
1198
|
+
Force exact search string matching (case sensitive)
|
1199
|
+
|
1200
|
+
|
1201
|
+
|
1107
1202
|
==== Command: <tt>rotate </tt>
|
1108
1203
|
Move entries to archive file
|
1109
1204
|
|
@@ -1154,6 +1249,16 @@ Tag filter, combine multiple tags with a comma. Added for compatibility with oth
|
|
1154
1249
|
[Default Value] None
|
1155
1250
|
|
1156
1251
|
|
1252
|
+
===== --not
|
1253
|
+
Rotate items that *don't* match search string or tag filter
|
1254
|
+
|
1255
|
+
|
1256
|
+
|
1257
|
+
===== -x|--exact
|
1258
|
+
Force exact search string matching (case sensitive)
|
1259
|
+
|
1260
|
+
|
1261
|
+
|
1157
1262
|
==== Command: <tt>sections </tt>
|
1158
1263
|
List sections
|
1159
1264
|
|
@@ -1260,11 +1365,21 @@ Use --no-menu to skip the interactive menu. Use with --query to filter items and
|
|
1260
1365
|
|
1261
1366
|
|
1262
1367
|
|
1368
|
+
===== --not
|
1369
|
+
Select items that *don't* match search/tag filters
|
1370
|
+
|
1371
|
+
|
1372
|
+
|
1263
1373
|
===== -r|--remove
|
1264
1374
|
Reverse -c, -f, --flag, and -t (remove instead of adding)
|
1265
1375
|
|
1266
1376
|
|
1267
1377
|
|
1378
|
+
===== -x|--exact
|
1379
|
+
Force exact search string matching (case sensitive)
|
1380
|
+
|
1381
|
+
|
1382
|
+
|
1268
1383
|
==== Command: <tt>show [SECTION|@TAGS]</tt>
|
1269
1384
|
List all entries
|
1270
1385
|
|
@@ -1366,6 +1481,11 @@ Select from a menu of matching entries to perform additional operations
|
|
1366
1481
|
|
1367
1482
|
|
1368
1483
|
|
1484
|
+
===== --not
|
1485
|
+
Show items that *don't* match search/tag/date filters
|
1486
|
+
|
1487
|
+
|
1488
|
+
|
1369
1489
|
===== --only_timed
|
1370
1490
|
Only show items with recorded time intervals
|
1371
1491
|
|
@@ -1381,6 +1501,11 @@ Show intervals with totals at the end of output
|
|
1381
1501
|
|
1382
1502
|
|
1383
1503
|
|
1504
|
+
===== -x|--exact
|
1505
|
+
Force exact search string matching (case sensitive)
|
1506
|
+
|
1507
|
+
|
1508
|
+
|
1384
1509
|
==== Command: <tt>since DATE_STRING</tt>
|
1385
1510
|
List entries since a date
|
1386
1511
|
|
@@ -1501,6 +1626,11 @@ Select item(s) to tag from a menu of matching entries
|
|
1501
1626
|
|
1502
1627
|
|
1503
1628
|
|
1629
|
+
===== --not
|
1630
|
+
Tag items that *don't* match search/tag filters
|
1631
|
+
|
1632
|
+
|
1633
|
+
|
1504
1634
|
===== -r|--remove
|
1505
1635
|
Remove given tag(s)
|
1506
1636
|
|
@@ -1516,6 +1646,11 @@ Tag last entry (or entries) not marked @done
|
|
1516
1646
|
|
1517
1647
|
|
1518
1648
|
|
1649
|
+
===== -x|--exact
|
1650
|
+
Force exact search string matching (case sensitive)
|
1651
|
+
|
1652
|
+
|
1653
|
+
|
1519
1654
|
==== Command: <tt>template TYPE</tt>
|
1520
1655
|
Output HTML, CSS, and Markdown (ERB) templates for customization
|
1521
1656
|
|
@@ -1690,6 +1825,11 @@ Select from a menu of matching entries to perform additional operations
|
|
1690
1825
|
|
1691
1826
|
|
1692
1827
|
|
1828
|
+
===== --not
|
1829
|
+
Show items that *don't* match search string
|
1830
|
+
|
1831
|
+
|
1832
|
+
|
1693
1833
|
===== --only_timed
|
1694
1834
|
Only show items with recorded time intervals (override view settings)
|
1695
1835
|
|
@@ -1705,6 +1845,11 @@ Show intervals with totals at the end of output
|
|
1705
1845
|
|
1706
1846
|
|
1707
1847
|
|
1848
|
+
===== -x|--exact
|
1849
|
+
Force exact search string matching (case sensitive)
|
1850
|
+
|
1851
|
+
|
1852
|
+
|
1708
1853
|
==== Command: <tt>views </tt>
|
1709
1854
|
List available custom views
|
1710
1855
|
|
data/lib/doing/errors.rb
CHANGED
data/lib/doing/item.rb
CHANGED
@@ -60,21 +60,22 @@ module Doing
|
|
60
60
|
@title.scan(/(?<= |\A)@([^\s(]+)/).map {|tag| tag[0]}.sort.uniq
|
61
61
|
end
|
62
62
|
|
63
|
-
def tags?(tags, bool = :and)
|
63
|
+
def tags?(tags, bool = :and, negate: false)
|
64
64
|
tags = split_tags(tags)
|
65
65
|
bool = bool.normalize_bool
|
66
66
|
|
67
|
-
case bool
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
67
|
+
matches = case bool
|
68
|
+
when :and
|
69
|
+
all_tags?(tags)
|
70
|
+
when :not
|
71
|
+
no_tags?(tags)
|
72
|
+
else
|
73
|
+
any_tags?(tags)
|
74
|
+
end
|
75
|
+
negate ? !matches : matches
|
75
76
|
end
|
76
77
|
|
77
|
-
def search(search)
|
78
|
+
def search(search, negate: false)
|
78
79
|
text = @title + @note.to_s
|
79
80
|
pattern = case search.strip
|
80
81
|
when %r{^/.*?/$}
|
@@ -88,7 +89,7 @@ module Doing
|
|
88
89
|
end
|
89
90
|
rx = Regexp.new(pattern, !case_sensitive)
|
90
91
|
|
91
|
-
text =~ rx
|
92
|
+
negate ? text !~ rx : text =~ rx
|
92
93
|
end
|
93
94
|
|
94
95
|
def should_finish?
|
@@ -64,9 +64,15 @@ module Doing
|
|
64
64
|
new_items.push(new_entry)
|
65
65
|
end
|
66
66
|
total = new_items.count
|
67
|
+
|
68
|
+
new_items = wwid.filter_items(new_items, opt: options)
|
69
|
+
filtered = total - new_items.count
|
70
|
+
Doing.logger.debug('Skipped:' , %(#{filtered} items that didn't match filter criteria)) if filtered.positive?
|
71
|
+
|
67
72
|
new_items = wwid.dedup(new_items, options[:no_overlap])
|
68
|
-
dups =
|
73
|
+
dups = filtered - new_items.count
|
69
74
|
Doing.logger.info(%(Skipped #{dups} items with overlapping times)) if dups.positive?
|
75
|
+
|
70
76
|
wwid.content[section][:items].concat(new_items)
|
71
77
|
Doing.logger.info(%(Imported #{new_items.count} items to #{section}))
|
72
78
|
end
|
@@ -40,13 +40,13 @@ module Doing
|
|
40
40
|
|
41
41
|
new_items = read_doing_file(path)
|
42
42
|
|
43
|
-
|
44
|
-
new_items = wwid.filter_items(new_items, opt: { count: 0, date_filter: options[:date_filter] })
|
45
|
-
end
|
43
|
+
total = new_items.count
|
46
44
|
|
47
|
-
|
48
|
-
|
49
|
-
|
45
|
+
options[:count] = 0
|
46
|
+
new_items = wwid.filter_items(new_items, opt: options)
|
47
|
+
|
48
|
+
skipped = total - new_items.count
|
49
|
+
Doing.logger.debug('Skipped:' , %(#{skipped} items that didn't match filter criteria)) if skipped.positive?
|
50
50
|
|
51
51
|
imported = []
|
52
52
|
|
@@ -66,9 +66,15 @@ module Doing
|
|
66
66
|
total = new_items.count
|
67
67
|
skipped = data.count - total
|
68
68
|
Doing.logger.debug('Skipped:' , %(#{skipped} items, invalid type or no time interval)) if skipped.positive?
|
69
|
+
|
70
|
+
new_items = wwid.filter_items(new_items, opt: options)
|
71
|
+
filtered = skipped - new_items.count
|
72
|
+
Doing.logger.debug('Skipped:' , %(#{filtered} items that didn't match filter criteria)) if filtered.positive?
|
73
|
+
|
69
74
|
new_items = wwid.dedup(new_items, options[:no_overlap])
|
70
|
-
dups =
|
75
|
+
dups = filtered - new_items.count
|
71
76
|
Doing.logger.debug('Skipped:' , %(#{dups} items with overlapping times)) if dups.positive?
|
77
|
+
|
72
78
|
wwid.content[section][:items].concat(new_items)
|
73
79
|
Doing.logger.info('Imported:', %(#{new_items.count} items to #{section}))
|
74
80
|
end
|
data/lib/doing/version.rb
CHANGED
data/lib/doing/wwid.rb
CHANGED
@@ -473,7 +473,7 @@ module Doing
|
|
473
473
|
duped = no_overlap ? item.overlapping_time?(comp) : item.same_time?(comp)
|
474
474
|
break if duped
|
475
475
|
end
|
476
|
-
logger.count(:skipped, level: :debug, message: 'overlapping %
|
476
|
+
logger.count(:skipped, level: :debug, message: '%count overlapping %items') if duped
|
477
477
|
# logger.log_now(:debug, 'Skipped:', "overlapping entry: #{item.title}") if duped
|
478
478
|
duped
|
479
479
|
end
|
@@ -686,20 +686,26 @@ module Doing
|
|
686
686
|
items.sort_by! { |item| [item.date, item.title.downcase] }.reverse
|
687
687
|
filtered_items = items.select do |item|
|
688
688
|
keep = true
|
689
|
-
|
690
|
-
|
689
|
+
if opt[:unfinished]
|
690
|
+
finished = item.tags?('done', :and)
|
691
|
+
finished = opt[:not] ? !finished : finished
|
692
|
+
keep = false if finished
|
693
|
+
end
|
691
694
|
|
692
695
|
if keep && opt[:tag]
|
693
696
|
opt[:tag_bool] ||= :and
|
694
697
|
tag_match = opt[:tag].nil? || opt[:tag].empty? ? true : item.tags?(opt[:tag], opt[:tag_bool])
|
695
698
|
keep = false unless tag_match
|
699
|
+
keep = opt[:not] ? !keep : keep
|
696
700
|
end
|
697
701
|
|
698
702
|
if keep && opt[:search]
|
699
703
|
search_match = opt[:search].nil? || opt[:search].empty? ? true : item.search(opt[:search])
|
700
704
|
keep = false unless search_match
|
705
|
+
keep = opt[:not] ? !keep : keep
|
701
706
|
end
|
702
707
|
|
708
|
+
|
703
709
|
if keep && opt[:date_filter]&.length == 2
|
704
710
|
start_date = opt[:date_filter][0]
|
705
711
|
end_date = opt[:date_filter][1]
|
@@ -710,30 +716,36 @@ module Doing
|
|
710
716
|
item.date.strftime('%F') == start_date.strftime('%F')
|
711
717
|
end
|
712
718
|
keep = false unless in_date_range
|
719
|
+
keep = opt[:not] ? !keep : keep
|
713
720
|
end
|
714
721
|
|
715
722
|
keep = false if keep && opt[:only_timed] && !item.interval
|
716
723
|
|
717
724
|
if keep && opt[:tag_filter] && !opt[:tag_filter]['tags'].empty?
|
718
725
|
keep = item.tags?(opt[:tag_filter]['tags'], opt[:tag_filter]['bool'])
|
726
|
+
keep = opt[:not] ? !keep : keep
|
719
727
|
end
|
720
728
|
|
721
729
|
if keep && opt[:before]
|
722
730
|
time_string = opt[:before]
|
723
731
|
cutoff = chronify(time_string, guess: :begin)
|
724
732
|
keep = cutoff && item.date <= cutoff
|
733
|
+
keep = opt[:not] ? !keep : keep
|
725
734
|
end
|
726
735
|
|
727
736
|
if keep && opt[:after]
|
728
737
|
time_string = opt[:after]
|
729
738
|
cutoff = chronify(time_string, guess: :end)
|
730
739
|
keep = cutoff && item.date >= cutoff
|
740
|
+
keep = opt[:not] ? !keep : keep
|
731
741
|
end
|
732
742
|
|
733
743
|
if keep && opt[:today]
|
734
744
|
keep = item.date >= Date.today.to_time && item.date < Date.today.next_day.to_time
|
745
|
+
keep = opt[:not] ? !keep : keep
|
735
746
|
elsif keep && opt[:yesterday]
|
736
747
|
keep = item.date >= Date.today.prev_day.to_time && item.date < Date.today.to_time
|
748
|
+
keep = opt[:not] ? !keep : keep
|
737
749
|
end
|
738
750
|
|
739
751
|
keep
|
@@ -755,7 +767,18 @@ module Doing
|
|
755
767
|
##
|
756
768
|
def interactive(opt = {})
|
757
769
|
section = opt[:section] ? guess_section(opt[:section]) : 'All'
|
770
|
+
|
771
|
+
search = nil
|
772
|
+
|
773
|
+
if opt[:search]
|
774
|
+
search = opt[:search]
|
775
|
+
search.sub!(/^'?/, "'") if opt[:exact]
|
776
|
+
search.downcase! if opt[:case] == false
|
777
|
+
opt[:search] = search
|
778
|
+
end
|
779
|
+
|
758
780
|
opt[:query] = opt[:search] if opt[:search] && !opt[:query]
|
781
|
+
opt[:query] = "!#{opt[:query]}" if opt[:not]
|
759
782
|
opt[:multiple] = true
|
760
783
|
items = filter_items([], opt: { section: section, search: opt[:search] })
|
761
784
|
|
@@ -1564,7 +1587,6 @@ module Doing
|
|
1564
1587
|
|
1565
1588
|
items.reverse! if opt[:order] =~ /^d/i
|
1566
1589
|
|
1567
|
-
|
1568
1590
|
if opt[:interactive]
|
1569
1591
|
opt[:menu] = !opt[:force]
|
1570
1592
|
opt[:query] = '' # opt[:search]
|
@@ -1875,7 +1897,7 @@ module Doing
|
|
1875
1897
|
end
|
1876
1898
|
|
1877
1899
|
opts[:search] = options[:search] if options[:search]
|
1878
|
-
|
1900
|
+
opts[:not] = options[:negate]
|
1879
1901
|
list_section(opts)
|
1880
1902
|
end
|
1881
1903
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: doing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.8.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brett Terpstra
|
@@ -231,10 +231,10 @@ files:
|
|
231
231
|
- lib/examples/commands/wiki.rb
|
232
232
|
- lib/examples/plugins/hooks.rb
|
233
233
|
- lib/examples/plugins/say_export.rb
|
234
|
-
- lib/examples/plugins/templates/wiki.css
|
235
|
-
- lib/examples/plugins/templates/wiki.haml
|
236
|
-
- lib/examples/plugins/templates/wiki_index.haml
|
237
|
-
- lib/examples/plugins/wiki_export.rb
|
234
|
+
- lib/examples/plugins/wiki_export/templates/wiki.css
|
235
|
+
- lib/examples/plugins/wiki_export/templates/wiki.haml
|
236
|
+
- lib/examples/plugins/wiki_export/templates/wiki_index.haml
|
237
|
+
- lib/examples/plugins/wiki_export/wiki_export.rb
|
238
238
|
- lib/helpers/fuzzyfilefinder
|
239
239
|
- lib/templates/doing-markdown.erb
|
240
240
|
- lib/templates/doing.css
|