doing 2.1.4pre → 2.1.5pre

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.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.yardoc/checksums +14 -13
  3. data/.yardoc/object_types +0 -0
  4. data/.yardoc/objects/root.dat +0 -0
  5. data/CHANGELOG.md +21 -0
  6. data/Gemfile.lock +3 -1
  7. data/README.md +1 -1
  8. data/bin/doing +149 -91
  9. data/doc/Array.html +63 -1
  10. data/doc/BooleanTermParser/Clause.html +293 -0
  11. data/doc/BooleanTermParser/Operator.html +172 -0
  12. data/doc/BooleanTermParser/Query.html +417 -0
  13. data/doc/BooleanTermParser/QueryParser.html +135 -0
  14. data/doc/BooleanTermParser/QueryTransformer.html +124 -0
  15. data/doc/BooleanTermParser.html +115 -0
  16. data/doc/Doing/CLIFormat.html +131 -0
  17. data/doc/Doing/Color.html +2 -2
  18. data/doc/Doing/Completion.html +1 -1
  19. data/doc/Doing/Configuration.html +116 -12
  20. data/doc/Doing/Errors/DoingNoTraceError.html +1 -1
  21. data/doc/Doing/Errors/DoingRuntimeError.html +1 -1
  22. data/doc/Doing/Errors/DoingStandardError.html +1 -1
  23. data/doc/Doing/Errors/EmptyInput.html +1 -1
  24. data/doc/Doing/Errors/NoResults.html +1 -1
  25. data/doc/Doing/Errors/PluginException.html +1 -1
  26. data/doc/Doing/Errors/UserCancelled.html +1 -1
  27. data/doc/Doing/Errors/WrongCommand.html +1 -1
  28. data/doc/Doing/Errors.html +1 -1
  29. data/doc/Doing/Hooks.html +1 -1
  30. data/doc/Doing/Item.html +100 -73
  31. data/doc/Doing/Items.html +2 -2
  32. data/doc/Doing/LogAdapter.html +70 -1
  33. data/doc/Doing/Note.html +5 -134
  34. data/doc/Doing/Pager.html +1 -1
  35. data/doc/Doing/Plugins.html +380 -40
  36. data/doc/Doing/Prompt.html +1 -1
  37. data/doc/Doing/Section.html +1 -1
  38. data/doc/Doing/TemplateString.html +713 -0
  39. data/doc/Doing/Util/Backup.html +686 -0
  40. data/doc/Doing/Util.html +1 -1
  41. data/doc/Doing/WWID.html +5 -5
  42. data/doc/Doing.html +4 -4
  43. data/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
  44. data/doc/GLI/Commands.html +1 -1
  45. data/doc/GLI.html +1 -1
  46. data/doc/Hash.html +1 -1
  47. data/doc/PhraseParser/Operator.html +172 -0
  48. data/doc/PhraseParser/PhraseClause.html +303 -0
  49. data/doc/PhraseParser/Query.html +495 -0
  50. data/doc/PhraseParser/QueryParser.html +136 -0
  51. data/doc/PhraseParser/QueryTransformer.html +124 -0
  52. data/doc/PhraseParser/TermClause.html +293 -0
  53. data/doc/PhraseParser.html +115 -0
  54. data/doc/Status.html +1 -1
  55. data/doc/String.html +182 -12
  56. data/doc/Symbol.html +35 -1
  57. data/doc/Time.html +1 -1
  58. data/doc/_index.html +21 -14
  59. data/doc/class_list.html +1 -1
  60. data/doc/file.README.html +2 -2
  61. data/doc/index.html +2 -2
  62. data/doc/method_list.html +319 -175
  63. data/doc/top-level-namespace.html +1 -1
  64. data/doing.gemspec +1 -0
  65. data/doing.rdoc +56 -9
  66. data/lib/doing/array.rb +9 -0
  67. data/lib/doing/configuration.rb +30 -8
  68. data/lib/doing/item.rb +12 -3
  69. data/lib/doing/log_adapter.rb +28 -0
  70. data/lib/doing/note.rb +31 -30
  71. data/lib/doing/plugin_manager.rb +57 -13
  72. data/lib/doing/plugins/export/dayone_export.rb +209 -0
  73. data/lib/doing/plugins/export/template_export.rb +90 -85
  74. data/lib/doing/prompt.rb +9 -6
  75. data/lib/doing/string.rb +68 -27
  76. data/lib/doing/symbol.rb +4 -0
  77. data/lib/doing/template_string.rb +197 -0
  78. data/lib/doing/util.rb +4 -2
  79. data/lib/doing/util_backup.rb +55 -3
  80. data/lib/doing/version.rb +1 -1
  81. data/lib/doing/wwid.rb +27 -18
  82. data/lib/doing.rb +3 -0
  83. data/lib/templates/doing-dayone-entry.erb +6 -0
  84. data/lib/templates/doing-dayone.erb +5 -0
  85. metadata +42 -2
data/bin/doing CHANGED
@@ -51,11 +51,16 @@ if ENV['DOING_LOG_LEVEL'] || ENV['DOING_DEBUG'] || ENV['DOING_QUIET'] || ENV['DO
51
51
  end
52
52
  end
53
53
 
54
+ Doing.logger.benchmark(:total, :start)
55
+
54
56
  if ENV['DOING_CONFIG']
55
57
  Doing.config_with(ENV['DOING_CONFIG'], { ignore_local: true })
56
58
  end
57
59
 
60
+ Doing.logger.benchmark(:configure, :start)
58
61
  config = Doing.config
62
+ Doing.logger.benchmark(:configure, :finish)
63
+
59
64
  settings = config.settings
60
65
  wwid.config = settings
61
66
 
@@ -224,14 +229,14 @@ command %i[reset begin] do |c|
224
229
  # c.switch [:fuzzy], default_value: false, negatable: false
225
230
 
226
231
  c.desc 'Force exact search string matching (case sensitive)'
227
- c.switch %i[x exact], default_value: false, negatable: false
232
+ c.switch %i[x exact], default_value: config.exact_match?, negatable: config.exact_match?
228
233
 
229
234
  c.desc 'Reset items that *don\'t* match search/tag filters'
230
235
  c.switch [:not], default_value: false, negatable: false
231
236
 
232
237
  c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
233
238
  c.arg_name 'TYPE'
234
- c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
239
+ c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
235
240
 
236
241
  c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
237
242
  c.arg_name 'BOOLEAN'
@@ -329,14 +334,14 @@ command :note do |c|
329
334
  # c.switch [:fuzzy], default_value: false, negatable: false
330
335
 
331
336
  c.desc 'Force exact search string matching (case sensitive)'
332
- c.switch %i[x exact], default_value: false, negatable: false
337
+ c.switch %i[x exact], default_value: config.exact_match?, negatable: config.exact_match?
333
338
 
334
339
  c.desc 'Add note to item that *doesn\'t* match search/tag filters'
335
340
  c.switch [:not], default_value: false, negatable: false
336
341
 
337
342
  c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
338
343
  c.arg_name 'TYPE'
339
- c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
344
+ c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
340
345
 
341
346
  c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans.'
342
347
  c.arg_name 'BOOLEAN'
@@ -599,14 +604,14 @@ command :select do |c|
599
604
  c.flag [:from]
600
605
 
601
606
  c.desc 'Force exact search string matching (case sensitive)'
602
- c.switch %i[x exact], default_value: false, negatable: false
607
+ c.switch %i[x exact], default_value: config.exact_match?, negatable: config.exact_match?
603
608
 
604
609
  c.desc 'Select items that *don\'t* match search/tag filters'
605
610
  c.switch [:not], default_value: false, negatable: false
606
611
 
607
612
  c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
608
613
  c.arg_name 'TYPE'
609
- c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
614
+ c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
610
615
 
611
616
  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.'
612
617
  c.switch %i[menu], negatable: true, default_value: true
@@ -940,14 +945,14 @@ command :cancel do |c|
940
945
  # c.switch [:fuzzy], default_value: false, negatable: false
941
946
 
942
947
  c.desc 'Force exact search string matching (case sensitive)'
943
- c.switch %i[x exact], default_value: false, negatable: false
948
+ c.switch %i[x exact], default_value: config.exact_match?, negatable: config.exact_match?
944
949
 
945
950
  c.desc 'Finish items that *don\'t* match search/tag filters'
946
951
  c.switch [:not], default_value: false, negatable: false
947
952
 
948
953
  c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
949
954
  c.arg_name 'TYPE'
950
- c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
955
+ c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
951
956
 
952
957
  c.desc 'Cancel last entry (or entries) not already marked @done'
953
958
  c.switch %i[u unfinished], negatable: false, default_value: false
@@ -1043,14 +1048,14 @@ command :finish do |c|
1043
1048
  # c.switch [:fuzzy], default_value: false, negatable: false
1044
1049
 
1045
1050
  c.desc 'Force exact search string matching (case sensitive)'
1046
- c.switch %i[x exact], default_value: false, negatable: false
1051
+ c.switch %i[x exact], default_value: config.exact_match?, negatable: config.exact_match?
1047
1052
 
1048
1053
  c.desc 'Finish items that *don\'t* match search/tag filters'
1049
1054
  c.switch [:not], default_value: false, negatable: false
1050
1055
 
1051
1056
  c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
1052
1057
  c.arg_name 'TYPE'
1053
- c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
1058
+ c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
1054
1059
 
1055
1060
  c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans.'
1056
1061
  c.arg_name 'BOOLEAN'
@@ -1182,14 +1187,14 @@ command %i[again resume] do |c|
1182
1187
  # c.switch [:fuzzy], default_value: false, negatable: false
1183
1188
 
1184
1189
  c.desc 'Force exact search string matching (case sensitive)'
1185
- c.switch %i[x exact], default_value: false, negatable: false
1190
+ c.switch %i[x exact], default_value: config.exact_match?, negatable: config.exact_match?
1186
1191
 
1187
1192
  c.desc 'Resume items that *don\'t* match search/tag filters'
1188
1193
  c.switch [:not], default_value: false, negatable: false
1189
1194
 
1190
1195
  c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
1191
1196
  c.arg_name 'TYPE'
1192
- c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
1197
+ c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
1193
1198
 
1194
1199
  c.desc 'Boolean used to combine multiple tags. Use PATTERN to parse + and - as booleans.'
1195
1200
  c.arg_name 'BOOLEAN'
@@ -1244,10 +1249,41 @@ command :tags do |c|
1244
1249
  c.arg_name 'ORDER'
1245
1250
  c.flag %i[o order], must_match: REGEX_SORT_ORDER, default_value: 'asc'
1246
1251
 
1252
+ c.desc 'Get tags for entries matching tags. Combine multiple tags with a comma. Wildcards allowed (*, ?).'
1253
+ c.arg_name 'TAG'
1254
+ c.flag [:tag]
1255
+
1256
+ c.desc 'Get tags for items matching search. Surround with
1257
+ slashes for regex (e.g. "/query/"), start with a single quote for exact match ("\'query").'
1258
+ c.arg_name 'QUERY'
1259
+ c.flag [:search]
1260
+
1261
+ # c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
1262
+ # c.switch [:fuzzy], default_value: false, negatable: false
1263
+
1264
+ c.desc 'Force exact search string matching (case sensitive)'
1265
+ c.switch %i[x exact], default_value: config.exact_match?, negatable: config.exact_match?
1266
+
1267
+ c.desc 'Get tags from items that *don\'t* match search/tag filters'
1268
+ c.switch [:not], default_value: false, negatable: false
1269
+
1270
+ c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
1271
+ c.arg_name 'TYPE'
1272
+ c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
1273
+
1274
+ c.desc 'Boolean used to combine multiple tags. Use PATTERN to parse + and - as booleans.'
1275
+ c.arg_name 'BOOLEAN'
1276
+ c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
1277
+
1278
+ c.desc 'Select items to scan from a menu of matching entries'
1279
+ c.switch %i[i interactive], negatable: false, default_value: false
1280
+
1247
1281
  c.action do |_global, options, args|
1248
1282
  section = wwid.guess_section(options[:section]) || options[:section].cap_first
1249
1283
 
1250
- items = wwid.content.in_section(section)
1284
+ items = wwid.filter_items([], opt: options)
1285
+
1286
+ # items = wwid.content.in_section(section)
1251
1287
  tags = wwid.all_tags(items, counts: true)
1252
1288
 
1253
1289
  if options[:sort] =~ /^n/i
@@ -1332,14 +1368,14 @@ command :tag do |c|
1332
1368
  # c.switch [:fuzzy], default_value: false, negatable: false
1333
1369
 
1334
1370
  c.desc 'Force exact search string matching (case sensitive)'
1335
- c.switch %i[x exact], default_value: false, negatable: false
1371
+ c.switch %i[x exact], default_value: config.exact_match?, negatable: config.exact_match?
1336
1372
 
1337
1373
  c.desc 'Tag items that *don\'t* match search/tag filters'
1338
1374
  c.switch [:not], default_value: false, negatable: false
1339
1375
 
1340
1376
  c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
1341
1377
  c.arg_name 'TYPE'
1342
- c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
1378
+ c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
1343
1379
 
1344
1380
  c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans.'
1345
1381
  c.arg_name 'BOOLEAN'
@@ -1395,37 +1431,41 @@ command :tag do |c|
1395
1431
  options[:search] = search
1396
1432
  end
1397
1433
 
1434
+ options[:count] = count
1435
+ options[:section] = section
1436
+ options[:tag] = search_tags
1437
+ options[:tags] = tags
1438
+ options[:tag_bool] = options[:bool].normalize_bool
1439
+
1398
1440
  if count.zero? && !options[:force]
1399
- if options[:search]
1400
- section_q = ' matching your search terms'
1401
- elsif options[:tag]
1402
- section_q = ' matching your tag search'
1403
- elsif section == 'All'
1404
- section_q = ''
1405
- else
1406
- section_q = " in section #{section}"
1407
- end
1441
+ matches = wwid.filter_items([], opt: options).count
1442
+
1443
+ if matches > 5
1444
+ if options[:search]
1445
+ section_q = ' matching your search terms'
1446
+ elsif options[:tag]
1447
+ section_q = ' matching your tag search'
1448
+ elsif section == 'All'
1449
+ section_q = ''
1450
+ else
1451
+ section_q = " in section #{section}"
1452
+ end
1408
1453
 
1409
1454
 
1410
- question = if options[:aarchive]
1411
- "Are you sure you want to autotag all records#{section_q}"
1412
- elsif options[:remove]
1413
- "Are you sure you want to remove #{tags.join(' and ')} from all records#{section_q}"
1414
- else
1415
- "Are you sure you want to add #{tags.join(' and ')} to all records#{section_q}"
1416
- end
1455
+ question = if options[:autotag]
1456
+ "Are you sure you want to autotag #{matches} records#{section_q}"
1457
+ elsif options[:remove]
1458
+ "Are you sure you want to remove #{tags.join(' and ')} from #{matches} records#{section_q}"
1459
+ else
1460
+ "Are you sure you want to add #{tags.join(' and ')} to #{matches} records#{section_q}"
1461
+ end
1417
1462
 
1418
- res = Doing::Prompt.yn(question, default_response: false)
1463
+ res = Doing::Prompt.yn(question, default_response: false)
1419
1464
 
1420
- raise UserCancelled unless res
1465
+ raise UserCancelled unless res
1466
+ end
1421
1467
  end
1422
1468
 
1423
- options[:count] = count
1424
- options[:section] = section
1425
- options[:tag] = search_tags
1426
- options[:tags] = tags
1427
- options[:tag_bool] = options[:bool].normalize_bool
1428
-
1429
1469
  wwid.tag_last(options)
1430
1470
  end
1431
1471
  end
@@ -1470,14 +1510,14 @@ command %i[mark flag] do |c|
1470
1510
  # c.switch [:fuzzy], default_value: false, negatable: false
1471
1511
 
1472
1512
  c.desc 'Force exact search string matching (case sensitive)'
1473
- c.switch %i[x exact], default_value: false, negatable: false
1513
+ c.switch %i[x exact], default_value: config.exact_match?, negatable: config.exact_match?
1474
1514
 
1475
1515
  c.desc 'Flag items that *don\'t* match search/tag/date filters'
1476
1516
  c.switch [:not], default_value: false, negatable: false
1477
1517
 
1478
1518
  c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
1479
1519
  c.arg_name 'TYPE'
1480
- c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
1520
+ c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
1481
1521
 
1482
1522
  c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans.'
1483
1523
  c.arg_name 'BOOLEAN'
@@ -1581,7 +1621,7 @@ command :show do |c|
1581
1621
 
1582
1622
  c.desc 'Max count to show'
1583
1623
  c.arg_name 'MAX'
1584
- c.flag %i[c count], default_value: 0
1624
+ c.flag %i[c count], default_value: 0, must_match: /^\d+$/, type: Integer
1585
1625
 
1586
1626
  c.desc 'Age (oldest|newest)'
1587
1627
  c.arg_name 'AGE'
@@ -1615,14 +1655,14 @@ command :show do |c|
1615
1655
  # c.switch [:fuzzy], default_value: false, negatable: false
1616
1656
 
1617
1657
  c.desc 'Force exact search string matching (case sensitive)'
1618
- c.switch %i[x exact], default_value: false, negatable: false
1658
+ c.switch %i[x exact], default_value: config.exact_match?, negatable: config.exact_match?
1619
1659
 
1620
1660
  c.desc 'Show items that *don\'t* match search/tag/date filters'
1621
1661
  c.switch [:not], default_value: false, negatable: false
1622
1662
 
1623
1663
  c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
1624
1664
  c.arg_name 'TYPE'
1625
- c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
1665
+ c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
1626
1666
 
1627
1667
  c.desc 'Sort order (asc/desc)'
1628
1668
  c.arg_name 'ORDER'
@@ -1699,24 +1739,11 @@ command :show do |c|
1699
1739
  end
1700
1740
  else
1701
1741
  section = options[:menu] ? wwid.choose_section(include_all: true) : settings['current_section']
1702
- end
1703
-
1704
- if options[:menu]
1705
- tag = wwid.choose_tag(section, include_all: true)
1706
- raise UserCancelled unless tag
1707
-
1708
- tags.concat(tag.split(/ +/).map { |t| t.strip.sub(/^@/, '') }) if tag =~ /^@/
1742
+ section ||= 'All'
1709
1743
  end
1710
1744
 
1711
1745
  tags.concat(options[:tag].to_tags) if options[:tag]
1712
1746
 
1713
- unless tags.empty?
1714
- tag_filter = {
1715
- 'tags' => tags,
1716
- 'bool' => options[:bool].normalize_bool
1717
- }
1718
- end
1719
-
1720
1747
  options[:times] = true if options[:totals]
1721
1748
 
1722
1749
  template = settings['templates']['default'].deep_merge({
@@ -1734,18 +1761,46 @@ command :show do |c|
1734
1761
  options[:search] = search
1735
1762
  end
1736
1763
 
1764
+ options[:section] = section
1765
+
1766
+ unless tags.empty?
1767
+ tag_filter = {
1768
+ 'tags' => tags,
1769
+ 'bool' => options[:bool].normalize_bool
1770
+ }
1771
+ end
1772
+
1773
+ options[:tag_filter] = tag_filter
1774
+ options[:tag] = nil
1775
+
1776
+ items = wwid.filter_items([], opt: options)
1777
+
1778
+ if options[:menu]
1779
+ tag = wwid.choose_tag(section, items: items, include_all: true)
1780
+ raise UserCancelled unless tag
1781
+
1782
+ # options[:bool] = :and unless tags.empty?
1783
+
1784
+ tags = tag.split(/ +/).map { |t| t.strip.sub(/^@?/, '') } if tag =~ /^@/
1785
+ unless tags.empty?
1786
+ tag_filter = {
1787
+ 'tags' => tags,
1788
+ 'bool' => options[:bool].normalize_bool
1789
+ }
1790
+ options[:tag_filter] = tag_filter
1791
+ end
1792
+ end
1793
+
1737
1794
  opt = options.dup
1738
1795
  opt[:sort_tags] = options[:tag_sort] =~ /^n/i
1739
1796
  opt[:count] = options[:count].to_i
1740
1797
  opt[:highlight] = true
1741
1798
  opt[:order] = options[:sort].normalize_order
1742
- opt[:section] = section
1743
1799
  opt[:tag] = nil
1744
- opt[:tag_filter] = tag_filter
1745
1800
  opt[:tag_order] = options[:tag_order].normalize_order
1746
1801
  opt[:tags_color] = template['tags_color']
1747
1802
 
1748
- Doing::Pager.page wwid.list_section(opt)
1803
+ Doing::Pager.page wwid.list_section(opt, items: items)
1749
1804
  end
1750
1805
  end
1751
1806
 
@@ -1812,14 +1867,14 @@ command %i[grep search] do |c|
1812
1867
  # c.switch [:fuzzy], default_value: false, negatable: false
1813
1868
 
1814
1869
  c.desc 'Force exact string matching (case sensitive)'
1815
- c.switch %i[x exact], default_value: false, negatable: false
1870
+ c.switch %i[x exact], default_value: config.exact_match?, negatable: config.exact_match?
1816
1871
 
1817
1872
  c.desc 'Show items that *don\'t* match search string'
1818
1873
  c.switch [:not], default_value: false, negatable: false
1819
1874
 
1820
1875
  c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
1821
1876
  c.arg_name 'TYPE'
1822
- c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
1877
+ c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
1823
1878
 
1824
1879
  c.desc 'Display an interactive menu of results to perform further operations'
1825
1880
  c.switch %i[i interactive], default_value: false, negatable: false
@@ -2204,14 +2259,14 @@ command :last do |c|
2204
2259
  # c.switch [:fuzzy], default_value: false, negatable: false
2205
2260
 
2206
2261
  c.desc 'Force exact search string matching (case sensitive)'
2207
- c.switch %i[x exact], default_value: false, negatable: false
2262
+ c.switch %i[x exact], default_value: config.exact_match?, negatable: config.exact_match?
2208
2263
 
2209
2264
  c.desc 'Show items that *don\'t* match search string or tag filter'
2210
2265
  c.switch [:not], default_value: false, negatable: false
2211
2266
 
2212
2267
  c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
2213
2268
  c.arg_name 'TYPE'
2214
- c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
2269
+ c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
2215
2270
 
2216
2271
  c.action do |global_options, options, _args|
2217
2272
  options[:fuzzy] = false
@@ -2221,17 +2276,7 @@ command :last do |c|
2221
2276
  tags = []
2222
2277
  else
2223
2278
  tags = options[:tag].to_tags
2224
- options[:bool] = case options[:bool]
2225
- when /^p/i
2226
- :pattern
2227
- when /(any|or)/i
2228
- :or
2229
- when /(not|none)/i
2230
- :not
2231
- else
2232
- :and
2233
- end
2234
-
2279
+ options[:bool] = options[:bool].normalize_bool
2235
2280
  end
2236
2281
 
2237
2282
  options[:case] = options[:case].normalize_case
@@ -2407,14 +2452,14 @@ command :view do |c|
2407
2452
  # c.switch [:fuzzy], default_value: false, negatable: false
2408
2453
 
2409
2454
  c.desc 'Force exact search string matching (case sensitive)'
2410
- c.switch %i[x exact], default_value: false, negatable: false
2455
+ c.switch %i[x exact], default_value: config.exact_match?, negatable: config.exact_match?
2411
2456
 
2412
2457
  c.desc 'Show items that *don\'t* match search string'
2413
2458
  c.switch [:not], default_value: false, negatable: false
2414
2459
 
2415
2460
  c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
2416
2461
  c.arg_name 'TYPE'
2417
- c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
2462
+ c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
2418
2463
 
2419
2464
  c.desc 'Sort tags by (name|time)'
2420
2465
  c.arg_name 'KEY'
@@ -2476,6 +2521,7 @@ command :view do |c|
2476
2521
  end
2477
2522
 
2478
2523
  view = wwid.get_view(title)
2524
+
2479
2525
  if view
2480
2526
  page_title = view.key?('title') ? view['title'] : title.cap_first
2481
2527
  only_timed = if (view.key?('only_timed') && view['only_timed']) || options[:only_timed]
@@ -2555,6 +2601,7 @@ command :view do |c|
2555
2601
  end
2556
2602
 
2557
2603
  opts = options.dup
2604
+ opts[:view_template] = title
2558
2605
  opts[:count] = count
2559
2606
  opts[:format] = date_format
2560
2607
  opts[:highlight] = options[:color]
@@ -2631,14 +2678,14 @@ command %i[archive move] do |c|
2631
2678
  # c.switch [:fuzzy], default_value: false, negatable: false
2632
2679
 
2633
2680
  c.desc 'Force exact search string matching (case sensitive)'
2634
- c.switch %i[x exact], default_value: false, negatable: false
2681
+ c.switch %i[x exact], default_value: config.exact_match?, negatable: config.exact_match?
2635
2682
 
2636
2683
  c.desc 'Show items that *don\'t* match search string'
2637
2684
  c.switch [:not], default_value: false, negatable: false
2638
2685
 
2639
2686
  c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
2640
2687
  c.arg_name 'TYPE'
2641
- c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
2688
+ c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
2642
2689
 
2643
2690
  c.desc 'Archive entries older than date
2644
2691
  (Flexible date format, e.g. 1/27/2021, 2020-07-19, or Monday 3pm)'
@@ -2716,14 +2763,14 @@ command :rotate do |c|
2716
2763
  # c.switch [:fuzzy], default_value: false, negatable: false
2717
2764
 
2718
2765
  c.desc 'Force exact search string matching (case sensitive)'
2719
- c.switch %i[x exact], default_value: false, negatable: false
2766
+ c.switch %i[x exact], default_value: config.exact_match?, negatable: config.exact_match?
2720
2767
 
2721
2768
  c.desc 'Rotate items that *don\'t* match search string or tag filter'
2722
2769
  c.switch [:not], default_value: false, negatable: false
2723
2770
 
2724
2771
  c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
2725
2772
  c.arg_name 'TYPE'
2726
- c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
2773
+ c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
2727
2774
 
2728
2775
  c.desc 'Rotate entries older than date
2729
2776
  (Flexible date format, e.g. 1/27/2021, 2020-07-19, or Monday 3pm)'
@@ -2930,7 +2977,7 @@ command :config do |c|
2930
2977
  c.command :undo do |undo|
2931
2978
  undo.action do |_global, options, args|
2932
2979
  config_file = config.choose_config
2933
- wwid.restore_backup(config_file)
2980
+ Doing::Util::Backup.restore_last_backup(config_file, count: 1)
2934
2981
  end
2935
2982
  end
2936
2983
 
@@ -3078,7 +3125,11 @@ command :undo do |c|
3078
3125
  if options[:prune]
3079
3126
  Doing::Util::Backup.prune_backups(file, options[:prune])
3080
3127
  elsif options[:redo]
3081
- Doing::Util::Backup.redo_backup(file, count: count)
3128
+ if options[:interactive]
3129
+ Doing::Util::Backup.select_redo(file)
3130
+ else
3131
+ Doing::Util::Backup.redo_backup(file, count: count)
3132
+ end
3082
3133
  else
3083
3134
  if options[:interactive]
3084
3135
  Doing::Util::Backup.select_backup(file)
@@ -3096,12 +3147,18 @@ command :redo do |c|
3096
3147
  c.arg_name 'PATH'
3097
3148
  c.flag %i[f file], default_value: wwid.doing_file
3098
3149
 
3150
+ c.desc 'Select from an interactive menu'
3151
+ c.switch %i[i interactive]
3152
+
3099
3153
  c.action do |_global, options, args|
3100
3154
  file = options[:file] || wwid.doing_file
3101
3155
  count = args.empty? ? 1 : args[0].to_i
3102
3156
  raise InvalidArgument, "Invalid count specified for redo" unless count&.positive?
3103
-
3104
- Doing::Util::Backup.redo_backup(file, count: count)
3157
+ if options[:interactive]
3158
+ Doing::Util::Backup.select_redo(file)
3159
+ else
3160
+ Doing::Util::Backup.redo_backup(file, count: count)
3161
+ end
3105
3162
  end
3106
3163
  end
3107
3164
 
@@ -3140,14 +3197,14 @@ command :import do |c|
3140
3197
  # c.switch [:fuzzy], default_value: false, negatable: false
3141
3198
 
3142
3199
  c.desc 'Force exact search string matching (case sensitive)'
3143
- c.switch %i[x exact], default_value: false, negatable: false
3200
+ c.switch %i[x exact], default_value: config.exact_match?, negatable: config.exact_match?
3144
3201
 
3145
3202
  c.desc 'Import items that *don\'t* match search/tag/date filters'
3146
3203
  c.switch [:not], default_value: false, negatable: false
3147
3204
 
3148
3205
  c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
3149
3206
  c.arg_name 'TYPE'
3150
- c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
3207
+ c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
3151
3208
 
3152
3209
  c.desc 'Only import items with recorded time intervals'
3153
3210
  c.switch [:only_timed], default_value: false, negatable: false
@@ -3222,7 +3279,6 @@ end
3222
3279
 
3223
3280
  pre do |global, _command, _options, _args|
3224
3281
  # global[:pager] ||= settings['paginate']
3225
-
3226
3282
  Doing::Pager.paginate = global[:pager]
3227
3283
 
3228
3284
  $stdout.puts "doing v#{Doing::VERSION}" if global[:version]
@@ -3253,6 +3309,8 @@ post do |global, _command, _options, _args|
3253
3309
  # Use skips_post before a command to skip this
3254
3310
  # block on that command only
3255
3311
  Doing.logger.output_results
3312
+ Doing.logger.benchmark(:total, :finish)
3313
+ Doing.logger.log_benchmarks
3256
3314
  end
3257
3315
 
3258
3316
  around do |global, command, options, arguments, code|
@@ -3286,13 +3344,13 @@ around do |global, command, options, arguments, code|
3286
3344
  config.config_file = cf
3287
3345
  settings = config.configure({ ignore_local: true })
3288
3346
  end
3289
-
3347
+ Doing.logger.benchmark(:init, :start)
3290
3348
  if global[:doing_file]
3291
3349
  wwid.init_doing_file(global[:doing_file])
3292
3350
  else
3293
3351
  wwid.init_doing_file
3294
3352
  end
3295
-
3353
+ Doing.logger.benchmark(:init, :finish)
3296
3354
  wwid.auto_tag = !global[:noauto]
3297
3355
 
3298
3356
  settings[:include_notes] = false unless global[:notes]
data/doc/Array.html CHANGED
@@ -194,6 +194,29 @@
194
194
  <span class="summary_desc"><div class='inline'><p>Convert array to nested hash, setting last key to value.</p>
195
195
  </div></span>
196
196
 
197
+ </li>
198
+
199
+
200
+ <li class="public ">
201
+ <span class="summary_signature">
202
+
203
+ <a href="#tags_to_array-instance_method" title="#tags_to_array (instance method)">#<strong>tags_to_array</strong> &#x21d2; Array </a>
204
+
205
+
206
+
207
+ </span>
208
+
209
+
210
+
211
+
212
+
213
+
214
+
215
+
216
+
217
+ <span class="summary_desc"><div class='inline'><p>Convert an @tags to plain strings.</p>
218
+ </div></span>
219
+
197
220
  </li>
198
221
 
199
222
 
@@ -402,6 +425,45 @@ with</p>
402
425
 
403
426
  </ul>
404
427
 
428
+ </div>
429
+ </div>
430
+
431
+ <div class="method_details ">
432
+ <h3 class="signature " id="tags_to_array-instance_method">
433
+
434
+ #<strong>tags_to_array</strong> &#x21d2; <tt><span class='object_link'><a href="" title="Array (class)">Array</a></span></tt>
435
+
436
+
437
+
438
+
439
+
440
+ </h3><div class="docstring">
441
+ <div class="discussion">
442
+ <p>Convert an @tags to plain strings</p>
443
+
444
+
445
+ </div>
446
+ </div>
447
+ <div class="tags">
448
+
449
+ <p class="tag_title">Returns:</p>
450
+ <ul class="return">
451
+
452
+ <li>
453
+
454
+
455
+ <span class='type'>(<tt><span class='object_link'><a href="" title="Array (class)">Array</a></span></tt>)</span>
456
+
457
+
458
+
459
+ &mdash;
460
+ <div class='inline'><p>array of strings</p>
461
+ </div>
462
+
463
+ </li>
464
+
465
+ </ul>
466
+
405
467
  </div>
406
468
  </div>
407
469
 
@@ -478,7 +540,7 @@ with</p>
478
540
  </div>
479
541
 
480
542
  <div id="footer">
481
- Generated on Fri Dec 17 16:17:18 2021 by
543
+ Generated on Sun Dec 19 12:35:33 2021 by
482
544
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
483
545
  0.9.26 (ruby-3.0.1).
484
546
  </div>