doing 2.0.8.pre → 2.0.9.pre

Sign up to get free protection for your applications and to get access to all the features.
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