doing 2.0.8.pre → 2.0.9.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 -20
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/bin/doing +145 -12
- data/doing.rdoc +143 -10
- data/lib/doing/item.rb +7 -2
- data/lib/doing/string.rb +22 -0
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +14 -9
- 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: f63df319758e6575ab75de3305ed9e44ac272d54b026e6873397970780115cca
|
4
|
+
data.tar.gz: e770a9679824aae9582ca1cedb23e783d0bb1070b1c740d7ce662d912124006d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 10bcf3f91db5636bb4133323b09a22f0978d3955e0e564931edef9cf8b9416aa4f7fa0480588dd85b95eab7cdb1f8952a843dce755bed6fc5dfd108ee60ea8ce
|
7
|
+
data.tar.gz: 23a73fa1f03cb28afaca764296a52140a6f7eb772add3db3220b255c51831cb5c2eb97a9f103000788fd06998bf8389dcac62618880a84fadfa5b209e1c718da
|
data/CHANGELOG.md
CHANGED
@@ -1,22 +1,14 @@
|
|
1
|
-
### 2.0.
|
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
|
-
|
8
|
-
### 2.0.7.pre
|
9
|
-
|
10
|
-
#### FIXED
|
11
|
-
|
12
|
-
- Zsh completion not outputting results
|
13
|
-
|
14
|
-
### 2.0.6.pre
|
1
|
+
### 2.0.9.pre
|
15
2
|
|
16
3
|
#### NEW
|
17
4
|
|
5
|
+
- Add 'timer_format' config with 'human' option for tag totals
|
18
6
|
- If `doing view` and `doing show` are confused, offer option to run the other command
|
19
7
|
- `doing completion` to generate shell completion scripts for zsh, bash, and fish
|
8
|
+
- --search and --not for cancel command
|
9
|
+
- --case flag for commands with --search. Can be (c)ase-sensitive, (i)nsensitive, or (s)mart (default smart, case insensitive unless search string contains uppercase letters)
|
10
|
+
- Add `--exact` flag to all commands with `--search` flag to force exact matching without requiring single quote prefix
|
11
|
+
- Add `--not` flag to all commands with filters (--tag, --search, --before, etc.) to negate the filter and return entries NOT matched
|
20
12
|
|
21
13
|
#### IMPROVED
|
22
14
|
|
@@ -27,16 +19,11 @@
|
|
27
19
|
|
28
20
|
#### FIXED
|
29
21
|
|
22
|
+
- Zsh completion not outputting results
|
30
23
|
- Remove `--[no]` from non-negatable options
|
31
24
|
- `doing plugins -t export -c` not outputting columns
|
32
25
|
- View config not respecting tag_order setting
|
33
26
|
|
34
|
-
### 2.0.5.pre
|
35
|
-
|
36
|
-
#### NEW
|
37
|
-
|
38
|
-
- Add 'timer_format' config with 'human' option for tag totals
|
39
|
-
|
40
27
|
### 2.0.3.pre
|
41
28
|
|
42
29
|
#### NEW
|
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.8<!--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
@@ -62,7 +62,10 @@ if settings.dig('plugins', 'command_path')
|
|
62
62
|
end
|
63
63
|
|
64
64
|
program_desc 'A CLI for a What Was I Doing system'
|
65
|
-
program_long_desc %(Doing uses a TaskPaper-like formatting to keep a plain text
|
65
|
+
program_long_desc %(Doing uses a TaskPaper-like formatting to keep a plain text
|
66
|
+
record of what you've been doing, complete with tag-based time tracking. The
|
67
|
+
command line tool allows you to add entries, annotate with tags and notes, and
|
68
|
+
view your entries with myriad options, with a focus on a "natural" language syntax.)
|
66
69
|
|
67
70
|
default_command :recent
|
68
71
|
# sort_help :manually
|
@@ -201,6 +204,10 @@ command %i[reset begin] do |c|
|
|
201
204
|
c.desc 'Reset items that *don\'t* match search/tag filters'
|
202
205
|
c.switch [:not], default_value: false, negatable: false
|
203
206
|
|
207
|
+
c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
|
208
|
+
c.arg_name 'TYPE'
|
209
|
+
c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
|
210
|
+
|
204
211
|
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
|
205
212
|
c.arg_name 'BOOLEAN'
|
206
213
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
|
@@ -213,7 +220,9 @@ command %i[reset begin] do |c|
|
|
213
220
|
options[:section] = wwid.guess_section(options[:section]) || options[:section].cap_first
|
214
221
|
end
|
215
222
|
|
216
|
-
options[:
|
223
|
+
options[:bool] = options[:bool].normalize_bool
|
224
|
+
|
225
|
+
options[:case] = options[:case].normalize_case
|
217
226
|
|
218
227
|
if options[:search]
|
219
228
|
search = options[:search]
|
@@ -261,6 +270,11 @@ long_desc %(
|
|
261
270
|
)
|
262
271
|
arg_name 'NOTE_TEXT'
|
263
272
|
command :note do |c|
|
273
|
+
c.example 'doing note', desc: 'Open the last entry in $EDITOR to append a note'
|
274
|
+
c.example 'doing note "Just a quick annotation"', desc: 'Add a quick note to the last entry'
|
275
|
+
c.example 'doing note --tag done "Keeping it real or something"', desc: 'Add a note to the last item tagged @done'
|
276
|
+
c.example 'doing note --search "late night" -e', desc: 'Open $EDITOR to add a note to the last item containing "late night" (fuzzy matched)'
|
277
|
+
|
264
278
|
c.desc 'Section'
|
265
279
|
c.arg_name 'NAME'
|
266
280
|
c.flag %i[s section], default_value: 'All'
|
@@ -285,6 +299,10 @@ command :note do |c|
|
|
285
299
|
c.desc 'Add note to item that *doesn\'t* match search/tag filters'
|
286
300
|
c.switch [:not], default_value: false, negatable: false
|
287
301
|
|
302
|
+
c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
|
303
|
+
c.arg_name 'TYPE'
|
304
|
+
c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
|
305
|
+
|
288
306
|
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
|
289
307
|
c.arg_name 'BOOLEAN'
|
290
308
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
|
@@ -299,6 +317,8 @@ command :note do |c|
|
|
299
317
|
|
300
318
|
options[:tag_bool] = options[:bool].normalize_bool
|
301
319
|
|
320
|
+
options[:case] = options[:case].normalize_case
|
321
|
+
|
302
322
|
if options[:search]
|
303
323
|
search = options[:search]
|
304
324
|
search.sub!(/^'?/, "'") if options[:exact]
|
@@ -356,6 +376,11 @@ end
|
|
356
376
|
desc 'Finish any running @meanwhile tasks and optionally create a new one'
|
357
377
|
arg_name 'ENTRY'
|
358
378
|
command :meanwhile do |c|
|
379
|
+
c.example 'doing meanwhile "Long task that will have others after it before it\'s done"', desc: 'Add a new long-running entry, completing any current @meanwhile entry'
|
380
|
+
c.example 'doing meanwhile', desc: 'Finish any open @meanwhile entry'
|
381
|
+
c.example 'doing meanwhile --archive', desc: 'Finish any open @meanwhile entry and archive it'
|
382
|
+
c.example 'doing meanwhile --back 2h "Something I\'ve been working on for a while', desc: 'Add a @meanwhile entry with a start date 2 hours ago'
|
383
|
+
|
359
384
|
c.desc 'Section'
|
360
385
|
c.arg_name 'NAME'
|
361
386
|
c.flag %i[s section]
|
@@ -422,12 +447,12 @@ end
|
|
422
447
|
desc 'Output HTML, CSS, and Markdown (ERB) templates for customization'
|
423
448
|
long_desc %(
|
424
449
|
Templates are printed to STDOUT for piping to a file.
|
425
|
-
Save them and use them in the configuration file under
|
426
|
-
|
427
|
-
Example `doing template haml > ~/styles/my_doing.haml`
|
450
|
+
Save them and use them in the configuration file under export_templates.
|
428
451
|
)
|
429
452
|
arg_name 'TYPE', must_match: Doing::Plugins.template_regex
|
430
453
|
command :template do |c|
|
454
|
+
c.example 'doing template haml > ~/styles/my_doing.haml', desc: 'Output the haml template and save it to a file'
|
455
|
+
|
431
456
|
c.desc 'List all available templates'
|
432
457
|
c.switch %i[l list], negatable: false
|
433
458
|
|
@@ -505,6 +530,10 @@ command :select do |c|
|
|
505
530
|
c.desc 'Select items that *don\'t* match search/tag filters'
|
506
531
|
c.switch [:not], default_value: false, negatable: false
|
507
532
|
|
533
|
+
c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
|
534
|
+
c.arg_name 'TYPE'
|
535
|
+
c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
|
536
|
+
|
508
537
|
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.'
|
509
538
|
c.switch %i[menu], negatable: true, default_value: true
|
510
539
|
|
@@ -542,6 +571,8 @@ command :select do |c|
|
|
542
571
|
|
543
572
|
raise InvalidArgument, '--no-menu requires --query' if !options[:menu] && !options[:query]
|
544
573
|
|
574
|
+
options[:case] = options[:case].normalize_case
|
575
|
+
|
545
576
|
wwid.interactive(options)
|
546
577
|
end
|
547
578
|
end
|
@@ -549,6 +580,9 @@ end
|
|
549
580
|
desc 'Add an item to the Later section'
|
550
581
|
arg_name 'ENTRY'
|
551
582
|
command :later do |c|
|
583
|
+
c.example 'doing later "Something I\'ll think about tomorrow"', desc: 'Add an entry to the Later section'
|
584
|
+
c.example 'doing later -e', desc: 'Open $EDITOR to create an entry and optional note'
|
585
|
+
|
552
586
|
c.desc "Edit entry with #{Doing::Util.default_editor}"
|
553
587
|
c.switch %i[e editor], negatable: false, default_value: false
|
554
588
|
|
@@ -598,6 +632,11 @@ end
|
|
598
632
|
desc 'Add a completed item with @done(date). No argument finishes last entry.'
|
599
633
|
arg_name 'ENTRY'
|
600
634
|
command %i[done did] do |c|
|
635
|
+
c.example 'doing done', desc: 'Tag the last entry @done'
|
636
|
+
c.example 'doing done I already finished this', desc: 'Add a new entry and immediately mark it @done'
|
637
|
+
c.example 'doing done --back 30m This took me half an hour', desc: 'Add an entry with a start date 30 minutes ago and a @done date of right now'
|
638
|
+
c.example 'doing done --at 3pm --took 1h Started and finished this afternoon', desc: 'Add an entry with a @done date of 3pm and a start date of 2pm (3pm - 1h)'
|
639
|
+
|
601
640
|
c.desc 'Remove @done tag'
|
602
641
|
c.switch %i[r remove], negatable: false, default_value: false
|
603
642
|
|
@@ -787,6 +826,9 @@ desc 'End last X entries with no time tracked'
|
|
787
826
|
long_desc 'Adds @done tag without datestamp so no elapsed time is recorded. Alias for `doing finish --no-date`.'
|
788
827
|
arg_name 'COUNT'
|
789
828
|
command :cancel do |c|
|
829
|
+
c.example 'doing cancel', desc: 'Cancel the last entry'
|
830
|
+
c.example 'doing cancel --tag project1 -u 5', desc: 'Cancel the last 5 unfinished entries containing @project1'
|
831
|
+
|
790
832
|
c.desc 'Archive entries'
|
791
833
|
c.switch %i[a archive], negatable: false, default_value: false
|
792
834
|
|
@@ -802,6 +844,20 @@ command :cancel do |c|
|
|
802
844
|
c.arg_name 'BOOLEAN'
|
803
845
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
|
804
846
|
|
847
|
+
c.desc 'Cancel the last X entries matching search filter, surround with slashes for regex (e.g. "/query.*/"), start with single quote for exact match ("\'query")'
|
848
|
+
c.arg_name 'QUERY'
|
849
|
+
c.flag [:search]
|
850
|
+
|
851
|
+
c.desc 'Force exact search string matching (case sensitive)'
|
852
|
+
c.switch %i[x exact], default_value: false, negatable: false
|
853
|
+
|
854
|
+
c.desc 'Finish items that *don\'t* match search/tag filters'
|
855
|
+
c.switch [:not], default_value: false, negatable: false
|
856
|
+
|
857
|
+
c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
|
858
|
+
c.arg_name 'TYPE'
|
859
|
+
c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
|
860
|
+
|
805
861
|
c.desc 'Cancel last entry (or entries) not already marked @done'
|
806
862
|
c.switch %i[u unfinished], negatable: false, default_value: false
|
807
863
|
|
@@ -831,7 +887,17 @@ command :cancel do |c|
|
|
831
887
|
count = args[0] ? args[0].to_i : 1
|
832
888
|
end
|
833
889
|
|
890
|
+
search = nil
|
891
|
+
|
892
|
+
if options[:search]
|
893
|
+
search = options[:search]
|
894
|
+
search.sub!(/^'?/, "'") if options[:exact]
|
895
|
+
end
|
896
|
+
|
834
897
|
opts = {
|
898
|
+
search: search,
|
899
|
+
case: options[:case].normalize_case,
|
900
|
+
not: options[:not],
|
835
901
|
archive: options[:a],
|
836
902
|
count: count,
|
837
903
|
date: false,
|
@@ -852,6 +918,10 @@ desc 'Mark last X entries as @done'
|
|
852
918
|
long_desc 'Marks the last X entries with a @done tag and current date. Does not alter already completed entries.'
|
853
919
|
arg_name 'COUNT'
|
854
920
|
command :finish do |c|
|
921
|
+
c.example 'doing finish', desc: 'Mark the last entry @done'
|
922
|
+
c.example 'doing finish --auto --section Later 10', desc: 'Add @done to any unfinished entries in the last 10 in Later, setting the finish time based on the start time of the task after it'
|
923
|
+
c.example 'doing finish --search "a specific entry" --at "yesterday 3pm"', desc: 'Search for an entry containing string and set its @done time to yesterday at 3pm'
|
924
|
+
|
855
925
|
c.desc 'Include date'
|
856
926
|
c.switch [:date], negatable: true, default_value: true
|
857
927
|
|
@@ -882,6 +952,10 @@ command :finish do |c|
|
|
882
952
|
c.desc 'Finish items that *don\'t* match search/tag filters'
|
883
953
|
c.switch [:not], default_value: false, negatable: false
|
884
954
|
|
955
|
+
c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
|
956
|
+
c.arg_name 'TYPE'
|
957
|
+
c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
|
958
|
+
|
885
959
|
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
|
886
960
|
c.arg_name 'BOOLEAN'
|
887
961
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
|
@@ -963,6 +1037,7 @@ command :finish do |c|
|
|
963
1037
|
count: count,
|
964
1038
|
date: options[:date],
|
965
1039
|
search: search,
|
1040
|
+
case: options[:case].normalize_case,
|
966
1041
|
not: options[:not],
|
967
1042
|
section: options[:section],
|
968
1043
|
sequential: options[:auto],
|
@@ -1003,6 +1078,10 @@ command %i[again resume] do |c|
|
|
1003
1078
|
c.desc 'Resume items that *don\'t* match search/tag filters'
|
1004
1079
|
c.switch [:not], default_value: false, negatable: false
|
1005
1080
|
|
1081
|
+
c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
|
1082
|
+
c.arg_name 'TYPE'
|
1083
|
+
c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
|
1084
|
+
|
1006
1085
|
c.desc 'Boolean used to combine multiple tags'
|
1007
1086
|
c.arg_name 'BOOLEAN'
|
1008
1087
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
|
@@ -1020,6 +1099,8 @@ command %i[again resume] do |c|
|
|
1020
1099
|
c.action do |_global_options, options, _args|
|
1021
1100
|
tags = options[:tag].nil? ? [] : options[:tag].to_tags
|
1022
1101
|
|
1102
|
+
options[:case] = options[:case].normalize_case
|
1103
|
+
|
1023
1104
|
if options[:search]
|
1024
1105
|
search = options[:search]
|
1025
1106
|
search.sub!(/^'?/, "'") if options[:exact]
|
@@ -1103,6 +1184,10 @@ command :tag do |c|
|
|
1103
1184
|
c.desc 'Tag items that *don\'t* match search/tag filters'
|
1104
1185
|
c.switch [:not], default_value: false, negatable: false
|
1105
1186
|
|
1187
|
+
c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
|
1188
|
+
c.arg_name 'TYPE'
|
1189
|
+
c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
|
1190
|
+
|
1106
1191
|
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
|
1107
1192
|
c.arg_name 'BOOLEAN'
|
1108
1193
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
|
@@ -1147,6 +1232,8 @@ command :tag do |c|
|
|
1147
1232
|
count = options[:count].to_i
|
1148
1233
|
end
|
1149
1234
|
|
1235
|
+
options[:case] = options[:case].normalize_case
|
1236
|
+
|
1150
1237
|
if options[:search]
|
1151
1238
|
search = options[:search]
|
1152
1239
|
search.sub!(/^'?/, "'") if options[:exact]
|
@@ -1229,6 +1316,10 @@ command [:mark, :flag] do |c|
|
|
1229
1316
|
c.desc 'Flag items that *don\'t* match search/tag/date filters'
|
1230
1317
|
c.switch [:not], default_value: false, negatable: false
|
1231
1318
|
|
1319
|
+
c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
|
1320
|
+
c.arg_name 'TYPE'
|
1321
|
+
c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
|
1322
|
+
|
1232
1323
|
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
|
1233
1324
|
c.arg_name 'BOOLEAN'
|
1234
1325
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
|
@@ -1260,6 +1351,8 @@ command [:mark, :flag] do |c|
|
|
1260
1351
|
count = options[:count].to_i
|
1261
1352
|
end
|
1262
1353
|
|
1354
|
+
options[:case] = options[:case].normalize_case
|
1355
|
+
|
1263
1356
|
if options[:search]
|
1264
1357
|
search = options[:search]
|
1265
1358
|
search.sub!(/^'?/, "'") if options[:exact]
|
@@ -1346,6 +1439,10 @@ command :show do |c|
|
|
1346
1439
|
c.desc 'Show items that *don\'t* match search/tag/date filters'
|
1347
1440
|
c.switch [:not], default_value: false, negatable: false
|
1348
1441
|
|
1442
|
+
c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
|
1443
|
+
c.arg_name 'TYPE'
|
1444
|
+
c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
|
1445
|
+
|
1349
1446
|
c.desc 'Sort order (asc/desc)'
|
1350
1447
|
c.arg_name 'ORDER'
|
1351
1448
|
c.flag %i[s sort], must_match: REGEX_SORT_ORDER, default_value: 'asc'
|
@@ -1450,6 +1547,8 @@ command :show do |c|
|
|
1450
1547
|
|
1451
1548
|
tags_color = settings.key?('tags_color') ? settings['tags_color'] : nil
|
1452
1549
|
|
1550
|
+
options[:case] = options[:case].normalize_case
|
1551
|
+
|
1453
1552
|
if options[:search]
|
1454
1553
|
search = options[:search]
|
1455
1554
|
search.sub!(/^'?/, "'") if options[:exact]
|
@@ -1521,12 +1620,13 @@ command %i[grep search] do |c|
|
|
1521
1620
|
c.desc 'Force exact string matching (case sensitive)'
|
1522
1621
|
c.switch %i[x exact], default_value: false, negatable: false
|
1523
1622
|
|
1524
|
-
c.desc 'Force case sensitive matching'
|
1525
|
-
c.switch %i[case]
|
1526
|
-
|
1527
1623
|
c.desc 'Show items that *don\'t* match search string'
|
1528
1624
|
c.switch [:not], default_value: false, negatable: false
|
1529
1625
|
|
1626
|
+
c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
|
1627
|
+
c.arg_name 'TYPE'
|
1628
|
+
c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
|
1629
|
+
|
1530
1630
|
c.desc 'Display an interactive menu of results to perform further operations'
|
1531
1631
|
c.switch %i[i interactive], default_value: false, negatable: false
|
1532
1632
|
|
@@ -1536,6 +1636,9 @@ command %i[grep search] do |c|
|
|
1536
1636
|
tags_color = settings.key?('tags_color') ? settings['tags_color'] : nil
|
1537
1637
|
|
1538
1638
|
section = wwid.guess_section(options[:section]) if options[:section]
|
1639
|
+
|
1640
|
+
options[:case] = options[:case].normalize_case
|
1641
|
+
|
1539
1642
|
search = args.join(' ')
|
1540
1643
|
search.sub!(/^'?/, "'") if options[:exact]
|
1541
1644
|
|
@@ -1866,6 +1969,10 @@ command :last do |c|
|
|
1866
1969
|
c.desc 'Show items that *don\'t* match search string or tag filter'
|
1867
1970
|
c.switch [:not], default_value: false, negatable: false
|
1868
1971
|
|
1972
|
+
c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
|
1973
|
+
c.arg_name 'TYPE'
|
1974
|
+
c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
|
1975
|
+
|
1869
1976
|
c.action do |global_options, options, _args|
|
1870
1977
|
raise InvalidArgument, '--tag and --search can not be used together' if options[:tag] && options[:search]
|
1871
1978
|
|
@@ -1884,6 +1991,8 @@ command :last do |c|
|
|
1884
1991
|
|
1885
1992
|
end
|
1886
1993
|
|
1994
|
+
options[:case] = options[:case].normalize_case
|
1995
|
+
|
1887
1996
|
search = nil
|
1888
1997
|
|
1889
1998
|
if options[:search]
|
@@ -1892,10 +2001,10 @@ command :last do |c|
|
|
1892
2001
|
end
|
1893
2002
|
|
1894
2003
|
if options[:editor]
|
1895
|
-
wwid.edit_last(section: options[:s], options: { search: search, tag: tags, tag_bool: options[:bool], not: options[:not] })
|
2004
|
+
wwid.edit_last(section: options[:s], options: { search: search, case: options[:case], tag: tags, tag_bool: options[:bool], not: options[:not] })
|
1896
2005
|
else
|
1897
2006
|
Doing::Pager::page wwid.last(times: true, section: options[:s],
|
1898
|
-
options: { search: search, negate: options[:not], tag: tags, tag_bool: options[:bool] }).strip
|
2007
|
+
options: { search: search, case: options[:case], negate: options[:not], tag: tags, tag_bool: options[:bool] }).strip
|
1899
2008
|
end
|
1900
2009
|
end
|
1901
2010
|
end
|
@@ -2059,6 +2168,10 @@ command :view do |c|
|
|
2059
2168
|
c.desc 'Show items that *don\'t* match search string'
|
2060
2169
|
c.switch [:not], default_value: false, negatable: false
|
2061
2170
|
|
2171
|
+
c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
|
2172
|
+
c.arg_name 'TYPE'
|
2173
|
+
c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
|
2174
|
+
|
2062
2175
|
c.desc 'Sort tags by (name|time)'
|
2063
2176
|
c.arg_name 'KEY'
|
2064
2177
|
c.flag [:tag_sort], must_match: /^(?:name|time)$/i
|
@@ -2190,6 +2303,8 @@ command :view do |c|
|
|
2190
2303
|
dates = [start, finish]
|
2191
2304
|
end
|
2192
2305
|
|
2306
|
+
options[:case] = options[:case].normalize_case
|
2307
|
+
|
2193
2308
|
search = nil
|
2194
2309
|
|
2195
2310
|
if options[:search]
|
@@ -2197,7 +2312,7 @@ command :view do |c|
|
|
2197
2312
|
search.sub!(/^'?/, "'") if options[:exact]
|
2198
2313
|
end
|
2199
2314
|
|
2200
|
-
opts = options
|
2315
|
+
opts = options.dup
|
2201
2316
|
opts[:search] = search
|
2202
2317
|
opts[:output] = output_format
|
2203
2318
|
opts[:count] = count
|
@@ -2277,6 +2392,10 @@ command %i[archive move] do |c|
|
|
2277
2392
|
c.desc 'Show items that *don\'t* match search string'
|
2278
2393
|
c.switch [:not], default_value: false, negatable: false
|
2279
2394
|
|
2395
|
+
c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
|
2396
|
+
c.arg_name 'TYPE'
|
2397
|
+
c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
|
2398
|
+
|
2280
2399
|
c.desc 'Archive entries older than date
|
2281
2400
|
(Flexible date format, e.g. 1/27/2021, 2020-07-19, or Monday 3pm)'
|
2282
2401
|
c.arg_name 'DATE_STRING'
|
@@ -2302,12 +2421,14 @@ command %i[archive move] do |c|
|
|
2302
2421
|
|
2303
2422
|
search = nil
|
2304
2423
|
|
2424
|
+
options[:case] = options[:case].normalize_case
|
2425
|
+
|
2305
2426
|
if options[:search]
|
2306
2427
|
search = options[:search]
|
2307
2428
|
search.sub!(/^'?/, "'") if options[:exact]
|
2308
2429
|
end
|
2309
2430
|
|
2310
|
-
opts = options
|
2431
|
+
opts = options.dup
|
2311
2432
|
opts[:search] = search
|
2312
2433
|
opts[:bool] = options[:bool].normalize_bool
|
2313
2434
|
opts[:destination] = options[:to]
|
@@ -2349,6 +2470,10 @@ command :rotate do |c|
|
|
2349
2470
|
c.desc 'Rotate items that *don\'t* match search string or tag filter'
|
2350
2471
|
c.switch [:not], default_value: false, negatable: false
|
2351
2472
|
|
2473
|
+
c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
|
2474
|
+
c.arg_name 'TYPE'
|
2475
|
+
c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
|
2476
|
+
|
2352
2477
|
c.desc 'Rotate entries older than date
|
2353
2478
|
(Flexible date format, e.g. 1/27/2021, 2020-07-19, or Monday 3pm)'
|
2354
2479
|
c.arg_name 'DATE_STRING'
|
@@ -2361,6 +2486,8 @@ command :rotate do |c|
|
|
2361
2486
|
|
2362
2487
|
options[:bool] = options[:bool].normalize_bool
|
2363
2488
|
|
2489
|
+
options[:case] = options[:case].normalize_case
|
2490
|
+
|
2364
2491
|
search = nil
|
2365
2492
|
|
2366
2493
|
if options[:search]
|
@@ -2563,6 +2690,10 @@ command :import do |c|
|
|
2563
2690
|
c.desc 'Import items that *don\'t* match search/tag/date filters'
|
2564
2691
|
c.switch [:not], default_value: false, negatable: false
|
2565
2692
|
|
2693
|
+
c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]'
|
2694
|
+
c.arg_name 'TYPE'
|
2695
|
+
c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
|
2696
|
+
|
2566
2697
|
c.desc 'Only import items with recorded time intervals'
|
2567
2698
|
c.switch [:only_timed], default_value: false, negatable: false
|
2568
2699
|
|
@@ -2620,6 +2751,8 @@ command :import do |c|
|
|
2620
2751
|
dates = [start, finish]
|
2621
2752
|
end
|
2622
2753
|
|
2754
|
+
options[:case] = options[:case].normalize_case
|
2755
|
+
|
2623
2756
|
if options[:type] =~ Doing::Plugins.plugin_regex(type: :import)
|
2624
2757
|
options[:no_overlap] = !options[:overlap]
|
2625
2758
|
options[:date_filter] = dates
|
data/doing.rdoc
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
== doing - A CLI for a What Was I Doing system
|
2
2
|
|
3
|
-
Doing uses a TaskPaper-like formatting to keep a plain text
|
3
|
+
Doing uses a TaskPaper-like formatting to keep a plain text
|
4
|
+
record of what you've been doing, complete with tag-based time tracking. The
|
5
|
+
command line tool allows you to add entries, annotate with tags and notes, and
|
6
|
+
view your entries with myriad options, with a focus on a "natural" language syntax.
|
4
7
|
|
5
|
-
v2.0.
|
8
|
+
v2.0.9.pre
|
6
9
|
|
7
10
|
=== Global Options
|
8
11
|
=== --config_file arg
|
@@ -87,6 +90,14 @@ Boolean used to combine multiple tags
|
|
87
90
|
[Must Match] (?i-mx:^(?:and|all|any|or|not|none)$)
|
88
91
|
|
89
92
|
|
93
|
+
===== --case TYPE
|
94
|
+
|
95
|
+
Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
|
96
|
+
|
97
|
+
[Default Value] smart
|
98
|
+
[Must Match] (?-mix:^[csi])
|
99
|
+
|
100
|
+
|
90
101
|
===== --in SECTION_NAME
|
91
102
|
|
92
103
|
Add new entry to section (default: same section as repeated entry)
|
@@ -167,6 +178,14 @@ Tag boolean (AND|OR|NOT)
|
|
167
178
|
[Must Match] (?i-mx:^(?:and|all|any|or|not|none)$)
|
168
179
|
|
169
180
|
|
181
|
+
===== --case TYPE
|
182
|
+
|
183
|
+
Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
|
184
|
+
|
185
|
+
[Default Value] smart
|
186
|
+
[Must Match] (?-mix:^[csi])
|
187
|
+
|
188
|
+
|
170
189
|
===== -k|--keep X
|
171
190
|
|
172
191
|
How many items to keep (ignored if archiving by tag or search)
|
@@ -284,6 +303,14 @@ Boolean (AND|OR|NOT) with which to combine multiple tag filters
|
|
284
303
|
[Must Match] (?i-mx:^(?:and|all|any|or|not|none)$)
|
285
304
|
|
286
305
|
|
306
|
+
===== --case TYPE
|
307
|
+
|
308
|
+
Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
|
309
|
+
|
310
|
+
[Default Value] smart
|
311
|
+
[Must Match] (?-mix:^[csi])
|
312
|
+
|
313
|
+
|
287
314
|
===== -s|--section NAME
|
288
315
|
|
289
316
|
Section
|
@@ -291,6 +318,13 @@ Section
|
|
291
318
|
[Default Value] None
|
292
319
|
|
293
320
|
|
321
|
+
===== --search QUERY
|
322
|
+
|
323
|
+
Cancel the last X entries matching search filter, surround with slashes for regex (e.g. "/query.*/"), start with single quote for exact match ("'query")
|
324
|
+
|
325
|
+
[Default Value] None
|
326
|
+
|
327
|
+
|
294
328
|
===== --tag TAG
|
295
329
|
|
296
330
|
Cancel the last X entries containing TAG. Separate multiple tags with comma (--tag=tag1,tag2)
|
@@ -308,11 +342,21 @@ Select item(s) to cancel from a menu of matching entries
|
|
308
342
|
|
309
343
|
|
310
344
|
|
345
|
+
===== --not
|
346
|
+
Finish items that *don't* match search/tag filters
|
347
|
+
|
348
|
+
|
349
|
+
|
311
350
|
===== -u|--unfinished
|
312
351
|
Cancel last entry (or entries) not already marked @done
|
313
352
|
|
314
353
|
|
315
354
|
|
355
|
+
===== -x|--exact
|
356
|
+
Force exact search string matching (case sensitive)
|
357
|
+
|
358
|
+
|
359
|
+
|
316
360
|
==== Command: <tt>choose </tt>
|
317
361
|
Select a section to display from a menu
|
318
362
|
|
@@ -493,6 +537,14 @@ Boolean (AND|OR|NOT) with which to combine multiple tag filters
|
|
493
537
|
[Must Match] (?i-mx:^(?:and|all|any|or|not|none)$)
|
494
538
|
|
495
539
|
|
540
|
+
===== --case TYPE
|
541
|
+
|
542
|
+
Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
|
543
|
+
|
544
|
+
[Default Value] smart
|
545
|
+
[Must Match] (?-mix:^[csi])
|
546
|
+
|
547
|
+
|
496
548
|
===== -s|--section NAME
|
497
549
|
|
498
550
|
Section
|
@@ -585,6 +637,14 @@ Constrain search to entries older than date
|
|
585
637
|
[Default Value] None
|
586
638
|
|
587
639
|
|
640
|
+
===== --case TYPE
|
641
|
+
|
642
|
+
Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
|
643
|
+
|
644
|
+
[Default Value] smart
|
645
|
+
[Must Match] (?-mix:^[csi])
|
646
|
+
|
647
|
+
|
588
648
|
===== -o|--output FORMAT
|
589
649
|
|
590
650
|
Output to export format (csv|doing|html|markdown|say|taskpaper|template|timeline|wiki)
|
@@ -607,11 +667,6 @@ Sort tags by (name|time)
|
|
607
667
|
[Must Match] (?i-mx:^(?:name|time)$)
|
608
668
|
|
609
669
|
|
610
|
-
===== --[no-]case
|
611
|
-
Force case sensitive matching
|
612
|
-
|
613
|
-
|
614
|
-
|
615
670
|
===== -i|--interactive
|
616
671
|
Display an interactive menu of results to perform further operations
|
617
672
|
|
@@ -671,6 +726,14 @@ Import entries older than date
|
|
671
726
|
[Default Value] None
|
672
727
|
|
673
728
|
|
729
|
+
===== --case TYPE
|
730
|
+
|
731
|
+
Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
|
732
|
+
|
733
|
+
[Default Value] smart
|
734
|
+
[Must Match] (?-mix:^[csi])
|
735
|
+
|
736
|
+
|
674
737
|
===== -f|--from DATE_OR_RANGE
|
675
738
|
|
676
739
|
Date range to import. Date range argument should be quoted. Date specifications can be natural language.
|
@@ -753,6 +816,14 @@ Tag boolean
|
|
753
816
|
[Must Match] (?i-mx:^(?:and|all|any|or|not|none)$)
|
754
817
|
|
755
818
|
|
819
|
+
===== --case TYPE
|
820
|
+
|
821
|
+
Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
|
822
|
+
|
823
|
+
[Default Value] smart
|
824
|
+
[Must Match] (?-mix:^[csi])
|
825
|
+
|
826
|
+
|
756
827
|
===== -s|--section NAME
|
757
828
|
|
758
829
|
Specify a section
|
@@ -834,6 +905,14 @@ How many recent entries to tag (0 for all)
|
|
834
905
|
[Must Match] (?-mix:^\d+$)
|
835
906
|
|
836
907
|
|
908
|
+
===== --case TYPE
|
909
|
+
|
910
|
+
Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
|
911
|
+
|
912
|
+
[Default Value] smart
|
913
|
+
[Must Match] (?-mix:^[csi])
|
914
|
+
|
915
|
+
|
837
916
|
===== -s|--section SECTION_NAME
|
838
917
|
|
839
918
|
Section
|
@@ -944,6 +1023,14 @@ Boolean (AND|OR|NOT) with which to combine multiple tag filters
|
|
944
1023
|
[Must Match] (?i-mx:^(?:and|all|any|or|not|none)$)
|
945
1024
|
|
946
1025
|
|
1026
|
+
===== --case TYPE
|
1027
|
+
|
1028
|
+
Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
|
1029
|
+
|
1030
|
+
[Default Value] smart
|
1031
|
+
[Must Match] (?-mix:^[csi])
|
1032
|
+
|
1033
|
+
|
947
1034
|
===== -s|--section NAME
|
948
1035
|
|
949
1036
|
Section
|
@@ -1158,6 +1245,14 @@ Boolean (AND|OR|NOT) with which to combine multiple tag filters
|
|
1158
1245
|
[Must Match] (?i-mx:^(?:and|all|any|or|not|none)$)
|
1159
1246
|
|
1160
1247
|
|
1248
|
+
===== --case TYPE
|
1249
|
+
|
1250
|
+
Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
|
1251
|
+
|
1252
|
+
[Default Value] smart
|
1253
|
+
[Must Match] (?-mix:^[csi])
|
1254
|
+
|
1255
|
+
|
1161
1256
|
===== -s|--section NAME
|
1162
1257
|
|
1163
1258
|
Limit search to section
|
@@ -1220,6 +1315,14 @@ Tag boolean (AND|OR|NOT)
|
|
1220
1315
|
[Must Match] (?i-mx:^(?:and|all|any|or|not|none)$)
|
1221
1316
|
|
1222
1317
|
|
1318
|
+
===== --case TYPE
|
1319
|
+
|
1320
|
+
Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
|
1321
|
+
|
1322
|
+
[Default Value] smart
|
1323
|
+
[Must Match] (?-mix:^[csi])
|
1324
|
+
|
1325
|
+
|
1223
1326
|
===== -k|--keep X
|
1224
1327
|
|
1225
1328
|
How many items to keep in each section (most recent)
|
@@ -1278,6 +1381,14 @@ Multiple selections are allowed, hit tab to add the highlighted entry to the
|
|
1278
1381
|
selection, and use ctrl-a to select all visible items. Return processes the
|
1279
1382
|
selected entries.
|
1280
1383
|
===== Options
|
1384
|
+
===== --case TYPE
|
1385
|
+
|
1386
|
+
Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
|
1387
|
+
|
1388
|
+
[Default Value] smart
|
1389
|
+
[Must Match] (?-mix:^[csi])
|
1390
|
+
|
1391
|
+
|
1281
1392
|
===== -m|--move SECTION
|
1282
1393
|
|
1283
1394
|
Move selected items to section
|
@@ -1422,6 +1533,14 @@ Max count to show
|
|
1422
1533
|
[Default Value] 0
|
1423
1534
|
|
1424
1535
|
|
1536
|
+
===== --case TYPE
|
1537
|
+
|
1538
|
+
Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
|
1539
|
+
|
1540
|
+
[Default Value] smart
|
1541
|
+
[Must Match] (?-mix:^[csi])
|
1542
|
+
|
1543
|
+
|
1425
1544
|
===== -f|--from DATE_OR_RANGE
|
1426
1545
|
|
1427
1546
|
Date range to show, or a single day to filter date on.
|
@@ -1577,6 +1696,14 @@ How many recent entries to tag (0 for all)
|
|
1577
1696
|
[Must Match] (?-mix:^\d+$)
|
1578
1697
|
|
1579
1698
|
|
1699
|
+
===== --case TYPE
|
1700
|
+
|
1701
|
+
Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
|
1702
|
+
|
1703
|
+
[Default Value] smart
|
1704
|
+
[Must Match] (?-mix:^[csi])
|
1705
|
+
|
1706
|
+
|
1580
1707
|
===== --rename ORIG_TAG
|
1581
1708
|
|
1582
1709
|
Replace existing tag with tag argument, wildcards (*,?) allowed, or use with --regex
|
@@ -1655,9 +1782,7 @@ Force exact search string matching (case sensitive)
|
|
1655
1782
|
Output HTML, CSS, and Markdown (ERB) templates for customization
|
1656
1783
|
|
1657
1784
|
Templates are printed to STDOUT for piping to a file.
|
1658
|
-
Save them and use them in the configuration file under
|
1659
|
-
|
1660
|
-
Example `doing template haml > ~/styles/my_doing.haml`
|
1785
|
+
Save them and use them in the configuration file under export_templates.
|
1661
1786
|
===== Options
|
1662
1787
|
===== -c
|
1663
1788
|
List in single column for completion
|
@@ -1771,6 +1896,14 @@ Count to display
|
|
1771
1896
|
[Must Match] (?-mix:^\d+$)
|
1772
1897
|
|
1773
1898
|
|
1899
|
+
===== --case TYPE
|
1900
|
+
|
1901
|
+
Case sensitivity for search string matching [(c)ase-sensitive, (i)nsensitive, (s)mart]
|
1902
|
+
|
1903
|
+
[Default Value] smart
|
1904
|
+
[Must Match] (?-mix:^[csi])
|
1905
|
+
|
1906
|
+
|
1774
1907
|
===== -o|--output FORMAT
|
1775
1908
|
|
1776
1909
|
Output to export format (csv|doing|html|markdown|say|taskpaper|template|timeline|wiki)
|
data/lib/doing/item.rb
CHANGED
@@ -75,7 +75,7 @@ module Doing
|
|
75
75
|
negate ? !matches : matches
|
76
76
|
end
|
77
77
|
|
78
|
-
def search(search, negate: false)
|
78
|
+
def search(search, negate: false, case_type: :smart)
|
79
79
|
text = @title + @note.to_s
|
80
80
|
pattern = case search.strip
|
81
81
|
when %r{^/.*?/$}
|
@@ -84,7 +84,12 @@ module Doing
|
|
84
84
|
case_sensitive = true
|
85
85
|
search.sub(/^'(.*?)'?$/, '\1')
|
86
86
|
else
|
87
|
-
|
87
|
+
if case_type == :smart
|
88
|
+
case_sensitive = true if search =~ /[A-Z]/
|
89
|
+
else
|
90
|
+
case_sensitive = case_type == :sensitive
|
91
|
+
end
|
92
|
+
|
88
93
|
search.split('').join('.{0,3}')
|
89
94
|
end
|
90
95
|
rx = Regexp.new(pattern, !case_sensitive)
|
data/lib/doing/string.rb
CHANGED
@@ -164,6 +164,28 @@ module Doing
|
|
164
164
|
end
|
165
165
|
end
|
166
166
|
|
167
|
+
##
|
168
|
+
## @brief Convert a case sensitivity string to a symbol
|
169
|
+
##
|
170
|
+
## @return Symbol :smart, :sensitive, :insensitive
|
171
|
+
##
|
172
|
+
def normalize_case!
|
173
|
+
replace normalize_case
|
174
|
+
end
|
175
|
+
|
176
|
+
def normalize_case(default = :smart)
|
177
|
+
case self
|
178
|
+
when /^c/i
|
179
|
+
:sensitive
|
180
|
+
when /^i/i
|
181
|
+
:insensitive
|
182
|
+
when /^s/i
|
183
|
+
:smart
|
184
|
+
else
|
185
|
+
default.is_a?(Symbol) ? default : default.normalize_case
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
167
189
|
##
|
168
190
|
## @brief Convert a boolean string to a symbol
|
169
191
|
##
|
data/lib/doing/version.rb
CHANGED
data/lib/doing/wwid.rb
CHANGED
@@ -700,12 +700,17 @@ module Doing
|
|
700
700
|
end
|
701
701
|
|
702
702
|
if keep && opt[:search]
|
703
|
-
|
703
|
+
opt[:case] = opt[:case].normalize_case unless opt[:case].is_a?(Symbol)
|
704
|
+
search_match = if opt[:search].nil? || opt[:search].empty?
|
705
|
+
true
|
706
|
+
else
|
707
|
+
item.search(opt[:search], case_type: opt[:case])
|
708
|
+
end
|
709
|
+
|
704
710
|
keep = false unless search_match
|
705
711
|
keep = opt[:not] ? !keep : keep
|
706
712
|
end
|
707
713
|
|
708
|
-
|
709
714
|
if keep && opt[:date_filter]&.length == 2
|
710
715
|
start_date = opt[:date_filter][0]
|
711
716
|
end_date = opt[:date_filter][1]
|
@@ -773,14 +778,13 @@ module Doing
|
|
773
778
|
if opt[:search]
|
774
779
|
search = opt[:search]
|
775
780
|
search.sub!(/^'?/, "'") if opt[:exact]
|
776
|
-
search.downcase! if opt[:case] == false
|
777
781
|
opt[:search] = search
|
778
782
|
end
|
779
783
|
|
780
784
|
opt[:query] = opt[:search] if opt[:search] && !opt[:query]
|
781
785
|
opt[:query] = "!#{opt[:query]}" if opt[:not]
|
782
786
|
opt[:multiple] = true
|
783
|
-
items = filter_items([], opt: { section: section, search: opt[:search] })
|
787
|
+
items = filter_items([], opt: { section: section, search: opt[:search], case: opt[:case] })
|
784
788
|
|
785
789
|
selection = choose_from_items(items, opt, include_section: section =~ /^all$/i)
|
786
790
|
|
@@ -957,7 +961,7 @@ module Doing
|
|
957
961
|
if opt[:delete]
|
958
962
|
res = opt[:force] ? true : yn("Delete #{items.size} items?", default_response: 'y')
|
959
963
|
if res
|
960
|
-
items.each { |item| delete_item(item) }
|
964
|
+
items.each { |item| delete_item(item, single: items.count == 1) }
|
961
965
|
write(@doing_file)
|
962
966
|
end
|
963
967
|
return
|
@@ -1015,7 +1019,7 @@ module Doing
|
|
1015
1019
|
title = input_lines[0]&.strip
|
1016
1020
|
|
1017
1021
|
if title.nil? || title =~ /^#{divider.strip}$/ || title.strip.empty?
|
1018
|
-
delete_item(items[i])
|
1022
|
+
delete_item(items[i], single: new_items.count == 1)
|
1019
1023
|
else
|
1020
1024
|
note = input_lines.length > 1 ? input_lines[1..-1] : []
|
1021
1025
|
|
@@ -1265,13 +1269,13 @@ module Doing
|
|
1265
1269
|
##
|
1266
1270
|
## @param item The item
|
1267
1271
|
##
|
1268
|
-
def delete_item(item)
|
1272
|
+
def delete_item(item, single: false)
|
1269
1273
|
section = item.section
|
1270
1274
|
|
1271
1275
|
section_items = @content[section][:items]
|
1272
1276
|
deleted = section_items.delete(item)
|
1273
1277
|
logger.count(:deleted)
|
1274
|
-
logger.info('Entry deleted:', deleted.title)
|
1278
|
+
logger.info('Entry deleted:', deleted.title) if single
|
1275
1279
|
end
|
1276
1280
|
|
1277
1281
|
##
|
@@ -1897,6 +1901,7 @@ module Doing
|
|
1897
1901
|
end
|
1898
1902
|
|
1899
1903
|
opts[:search] = options[:search] if options[:search]
|
1904
|
+
opts[:case] = options[:case]
|
1900
1905
|
opts[:not] = options[:negate]
|
1901
1906
|
list_section(opts)
|
1902
1907
|
end
|
@@ -2070,7 +2075,7 @@ EOS
|
|
2070
2075
|
(max - k.length).times do
|
2071
2076
|
spacer += ' '
|
2072
2077
|
end
|
2073
|
-
|
2078
|
+
_d, h, m = format_time(v, human: true)
|
2074
2079
|
output.push("┃ #{spacer}#{k}:#{format('%<h> 4dh %<m>02dm', h: h, m: m)} ┃")
|
2075
2080
|
end
|
2076
2081
|
|