doing 2.0.7.pre → 2.0.8.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/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
|