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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 395218e7fd0178eb8d626e58c6b4ec078ff2631506829f98e7a41daacc7dd9bc
4
- data.tar.gz: c7bda7d2e832b3f657f409c512f16bf71b8d0b247b776c4f3ce467c399482241
3
+ metadata.gz: f63df319758e6575ab75de3305ed9e44ac272d54b026e6873397970780115cca
4
+ data.tar.gz: e770a9679824aae9582ca1cedb23e783d0bb1070b1c740d7ce662d912124006d
5
5
  SHA512:
6
- metadata.gz: 73d7cfcafe737b446a6fec46a8bb8ae41503137240546cd361b1f6f292ecbf6a37c361a4708aeb9a4efcfddf76e42515e580a6c03b86c5512082e90e2bd8b325
7
- data.tar.gz: 4f5ccc666a48629fe674923dfece11a872b59b5af7329f7484c777b4cc6166bebb287df5f19ea2d802212e553d03a2ac4b853f31c1f41f4204b6293838cd2695
6
+ metadata.gz: 10bcf3f91db5636bb4133323b09a22f0978d3955e0e564931edef9cf8b9416aa4f7fa0480588dd85b95eab7cdb1f8952a843dce755bed6fc5dfd108ee60ea8ce
7
+ data.tar.gz: 23a73fa1f03cb28afaca764296a52140a6f7eb772add3db3220b255c51831cb5c2eb97a9f103000788fd06998bf8389dcac62618880a84fadfa5b209e1c718da
data/CHANGELOG.md CHANGED
@@ -1,22 +1,14 @@
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
-
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- doing (2.0.8.pre)
4
+ doing (2.0.9.pre)
5
5
  chronic (~> 0.10, >= 0.10.2)
6
6
  deep_merge (~> 1.2, >= 1.2.1)
7
7
  gli (~> 2.19, >= 2.19.2)
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.7<!--END VER-->.
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 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.)
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[:tag_bool] = options[:bool].normalize_bool
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 html_template.
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 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.
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.pre
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 html_template.
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
- case_sensitive = true if search =~ /[A-Z]/
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
@@ -1,3 +1,3 @@
1
1
  module Doing
2
- VERSION = '2.0.8.pre'
2
+ VERSION = '2.0.9.pre'
3
3
  end
data/lib/doing/wwid.rb CHANGED
@@ -700,12 +700,17 @@ module Doing
700
700
  end
701
701
 
702
702
  if keep && opt[:search]
703
- search_match = opt[:search].nil? || opt[:search].empty? ? true : item.search(opt[:search])
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
- d, h, m = format_time(v, human: true)
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
 
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.8.pre
4
+ version: 2.0.9.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra