doing 2.1.24 → 2.1.28

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 (170) hide show
  1. checksums.yaml +4 -4
  2. data/.yardoc/checksums +17 -21
  3. data/.yardoc/object_types +0 -0
  4. data/.yardoc/objects/root.dat +0 -0
  5. data/CHANGELOG.md +325 -102
  6. data/Dockerfile +5 -5
  7. data/Dockerfile-2.6 +5 -5
  8. data/Dockerfile-2.7 +5 -4
  9. data/Dockerfile-3.0 +5 -4
  10. data/Gemfile.lock +1 -1
  11. data/README.md +1 -1
  12. data/Rakefile +3 -3
  13. data/bin/commands/add_section.rb +15 -0
  14. data/bin/commands/again.rb +57 -0
  15. data/bin/commands/archive.rb +55 -0
  16. data/bin/commands/cancel.rb +60 -0
  17. data/bin/commands/changes.rb +73 -0
  18. data/bin/commands/choose.rb +9 -0
  19. data/bin/commands/colors.rb +21 -0
  20. data/bin/commands/commands.rb +89 -0
  21. data/bin/commands/commands_accepting.rb +76 -0
  22. data/bin/commands/completion.rb +27 -0
  23. data/bin/commands/config.rb +245 -0
  24. data/bin/commands/done.rb +235 -0
  25. data/bin/commands/finish.rb +126 -0
  26. data/bin/commands/flag.rb +90 -0
  27. data/bin/commands/grep.rb +108 -0
  28. data/bin/commands/import.rb +71 -0
  29. data/bin/commands/install_fzf.rb +17 -0
  30. data/bin/commands/last.rb +81 -0
  31. data/bin/commands/meanwhile.rb +76 -0
  32. data/bin/commands/note.rb +91 -0
  33. data/bin/commands/now.rb +145 -0
  34. data/bin/commands/on.rb +65 -0
  35. data/bin/commands/open.rb +53 -0
  36. data/bin/commands/plugins.rb +23 -0
  37. data/bin/commands/recent.rb +77 -0
  38. data/bin/commands/redo.rb +26 -0
  39. data/bin/commands/reset.rb +73 -0
  40. data/bin/commands/rotate.rb +42 -0
  41. data/bin/commands/sections.rb +11 -0
  42. data/bin/commands/select.rb +105 -0
  43. data/bin/commands/show.rb +185 -0
  44. data/bin/commands/since.rb +63 -0
  45. data/bin/commands/tag.rb +149 -0
  46. data/bin/commands/tag_dir.rb +29 -0
  47. data/bin/commands/tags.rb +66 -0
  48. data/bin/commands/template.rb +61 -0
  49. data/bin/commands/today.rb +64 -0
  50. data/bin/commands/undo.rb +49 -0
  51. data/bin/commands/view.rb +201 -0
  52. data/bin/commands/views.rb +11 -0
  53. data/bin/commands/yesterday.rb +72 -0
  54. data/bin/doing +241 -3662
  55. data/docs/doc/Array.html +13 -449
  56. data/docs/doc/BooleanTermParser/Clause.html +5 -5
  57. data/docs/doc/BooleanTermParser/Operator.html +4 -4
  58. data/docs/doc/BooleanTermParser/Query.html +8 -8
  59. data/docs/doc/BooleanTermParser/QueryParser.html +2 -2
  60. data/docs/doc/BooleanTermParser/QueryTransformer.html +2 -2
  61. data/docs/doc/BooleanTermParser.html +1 -1
  62. data/docs/doc/Doing/Color.html +65 -59
  63. data/docs/doc/Doing/Completion.html +2 -2
  64. data/docs/doc/Doing/Configuration.html +49 -16
  65. data/docs/doc/Doing/Errors/DoingNoTraceError.html +2 -2
  66. data/docs/doc/Doing/Errors/DoingRuntimeError.html +2 -2
  67. data/docs/doc/Doing/Errors/DoingStandardError.html +2 -2
  68. data/docs/doc/Doing/Errors/EmptyInput.html +2 -2
  69. data/docs/doc/Doing/Errors/NoResults.html +2 -2
  70. data/docs/doc/Doing/Errors/PluginException.html +3 -3
  71. data/docs/doc/Doing/Errors/UserCancelled.html +2 -2
  72. data/docs/doc/Doing/Errors/WrongCommand.html +2 -2
  73. data/docs/doc/Doing/Errors.html +1 -1
  74. data/docs/doc/Doing/Hooks.html +6 -6
  75. data/docs/doc/Doing/Item.html +50 -16
  76. data/docs/doc/Doing/Items.html +10 -10
  77. data/docs/doc/Doing/LogAdapter.html +24 -24
  78. data/docs/doc/Doing/Note.html +7 -7
  79. data/docs/doc/Doing/Pager.html +4 -4
  80. data/docs/doc/Doing/Plugins.html +7 -7
  81. data/docs/doc/Doing/Prompt.html +59 -14
  82. data/docs/doc/Doing/Section.html +6 -6
  83. data/docs/doc/Doing/TemplateString.html +8 -8
  84. data/docs/doc/Doing/Types.html +46 -1
  85. data/docs/doc/Doing/Util/Backup.html +10 -10
  86. data/docs/doc/Doing/Util.html +15 -15
  87. data/docs/doc/Doing/WWID.html +73 -61
  88. data/docs/doc/Doing.html +3 -3
  89. data/docs/doc/FalseClass.html +235 -0
  90. data/docs/doc/GLI/Commands/Help.html +3 -3
  91. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +17 -17
  92. data/docs/doc/GLI/Commands.html +1 -1
  93. data/docs/doc/GLI.html +1 -1
  94. data/docs/doc/Hash.html +45 -11
  95. data/docs/doc/Numeric.html +5 -5
  96. data/docs/doc/Object.html +203 -0
  97. data/docs/doc/PhraseParser/Operator.html +4 -4
  98. data/docs/doc/PhraseParser/PhraseClause.html +5 -5
  99. data/docs/doc/PhraseParser/Query.html +10 -10
  100. data/docs/doc/PhraseParser/QueryParser.html +2 -2
  101. data/docs/doc/PhraseParser/QueryTransformer.html +2 -2
  102. data/docs/doc/PhraseParser/TermClause.html +5 -5
  103. data/docs/doc/PhraseParser.html +1 -1
  104. data/docs/doc/Status.html +7 -7
  105. data/docs/doc/String.html +306 -3111
  106. data/docs/doc/Symbol.html +45 -11
  107. data/docs/doc/Time.html +6 -6
  108. data/docs/doc/TrueClass.html +235 -0
  109. data/docs/doc/_index.html +37 -19
  110. data/docs/doc/class_list.html +1 -1
  111. data/docs/doc/file.README.html +2 -2
  112. data/docs/doc/index.html +2 -2
  113. data/docs/doc/method_list.html +240 -576
  114. data/docs/doc/top-level-namespace.html +2 -2
  115. data/doing.rdoc +297 -169
  116. data/example_plugin.rb +2 -2
  117. data/lib/completion/_doing.zsh +35 -31
  118. data/lib/completion/doing.bash +30 -19
  119. data/lib/completion/doing.fish +81 -67
  120. data/lib/doing/array/array.rb +4 -0
  121. data/lib/doing/array/nested_hash.rb +17 -0
  122. data/lib/doing/{array.rb → array/tags.rb} +7 -25
  123. data/lib/doing/changelog/change.rb +26 -11
  124. data/lib/doing/changelog/changes.rb +16 -4
  125. data/lib/doing/{array_chronify.rb → chronify/array.rb} +0 -0
  126. data/lib/doing/chronify/chronify.rb +5 -0
  127. data/lib/doing/{numeric_chronify.rb → chronify/numeric.rb} +0 -0
  128. data/lib/doing/{string_chronify.rb → chronify/string.rb} +0 -0
  129. data/lib/doing/colors.rb +115 -54
  130. data/lib/doing/configuration.rb +9 -6
  131. data/lib/doing/good.rb +72 -0
  132. data/lib/doing/hash.rb +4 -0
  133. data/lib/doing/help_monkey_patch.rb +6 -5
  134. data/lib/doing/hooks.rb +3 -3
  135. data/lib/doing/item.rb +19 -15
  136. data/lib/doing/items.rb +2 -2
  137. data/lib/doing/log_adapter.rb +35 -2
  138. data/lib/doing/normalize.rb +188 -0
  139. data/lib/doing/pager.rb +1 -0
  140. data/lib/doing/plugins/export/dayone_export.rb +1 -1
  141. data/lib/doing/plugins/export/html_export.rb +1 -1
  142. data/lib/doing/plugins/export/json_export.rb +1 -1
  143. data/lib/doing/plugins/export/markdown_export.rb +1 -1
  144. data/lib/doing/plugins/export/template_export.rb +3 -1
  145. data/lib/doing/plugins/import/calendar_import.rb +1 -1
  146. data/lib/doing/plugins/import/doing_import.rb +1 -1
  147. data/lib/doing/plugins/import/timing_import.rb +1 -1
  148. data/lib/doing/prompt.rb +9 -3
  149. data/lib/doing/string/highlight.rb +95 -0
  150. data/lib/doing/string/query.rb +129 -0
  151. data/lib/doing/string/string.rb +12 -0
  152. data/lib/doing/string/tags.rb +164 -0
  153. data/lib/doing/string/transform.rb +168 -0
  154. data/lib/doing/string/truncate.rb +75 -0
  155. data/lib/doing/string/url.rb +82 -0
  156. data/lib/doing/template_string.rb +2 -24
  157. data/lib/doing/types.rb +9 -0
  158. data/lib/doing/util.rb +20 -16
  159. data/lib/doing/version.rb +1 -1
  160. data/lib/doing/wwid.rb +91 -51
  161. data/lib/doing.rb +5 -6
  162. data/lib/examples/commands/wiki.rb +6 -7
  163. data/lib/examples/plugins/wiki_export/wiki_export.rb +1 -1
  164. data/lib/helpers/threaded_tests.rb +69 -79
  165. data/lib/helpers/threaded_tests_string.rb +50 -0
  166. data/scripts/deploy.rb +107 -0
  167. data/scripts/runtests.sh +4 -0
  168. metadata +65 -8
  169. data/lib/doing/string.rb +0 -765
  170. data/lib/doing/symbol.rb +0 -28
data/lib/doing/wwid.rb CHANGED
@@ -338,6 +338,7 @@ module Doing
338
338
  ## @option opt :note [Array] item note (will be converted if value is String)
339
339
  ## @option opt :back [Date] backdate
340
340
  ## @option opt :timed [Boolean] new item is timed entry, marks previous entry as @done
341
+ ## @option opt :done [Date] If set, adds a @done tag to new entry
341
342
  ##
342
343
  def add_item(title, section = nil, opt)
343
344
  opt ||= {}
@@ -360,9 +361,18 @@ module Doing
360
361
 
361
362
  title.compress!
362
363
  entry = Item.new(opt[:back], title.strip, section)
364
+
365
+ if opt[:done] && entry.should_finish?
366
+ if entry.should_time?
367
+ entry.tag('done', value: opt[:done])
368
+ else
369
+ entry.tag('done')
370
+ end
371
+ end
372
+
363
373
  entry.note = note
364
374
 
365
- items = @content.dup
375
+ items = @content.clone
366
376
  if opt[:timed]
367
377
  items.reverse!
368
378
  items.each_with_index do |i, x|
@@ -380,7 +390,8 @@ module Doing
380
390
  # logger.count(:added, level: :debug)
381
391
  logger.info('New entry:', %(added "#{entry.date.relative_date}: #{entry.title}" to #{section}))
382
392
 
383
- Hooks.trigger :post_entry_added, self, entry.dup
393
+ Hooks.trigger :post_entry_added, self, entry
394
+ entry
384
395
  end
385
396
 
386
397
  ##
@@ -474,6 +485,7 @@ module Doing
474
485
  #
475
486
  def repeat_item(item, opt)
476
487
  opt ||= {}
488
+ old_item = item.clone
477
489
  if item.should_finish?
478
490
  if item.should_time?
479
491
  finish_date = verify_duration(item.date, Time.now, title: item.title)
@@ -481,7 +493,7 @@ module Doing
481
493
  else
482
494
  item.title.tag!('done')
483
495
  end
484
- Hooks.trigger :post_entry_updated, self, item
496
+ Hooks.trigger :post_entry_updated, self, item, old_item
485
497
  end
486
498
 
487
499
  # Remove @done tag
@@ -647,11 +659,12 @@ module Doing
647
659
  ## @option opt [Array] :val (nil) Array of tag value queries
648
660
  ##
649
661
  def filter_items(items = Items.new, opt: {})
662
+ logger.benchmark(:filter_items, :start)
650
663
  time_rx = /^(\d{1,2}+(:\d{1,2}+)?( *(am|pm))?|midnight|noon)$/
651
664
 
652
665
  if items.nil? || items.empty?
653
666
  section = opt[:section] ? guess_section(opt[:section]) : 'All'
654
- items = section =~ /^all$/i ? @content.dup : @content.in_section(section)
667
+ items = section =~ /^all$/i ? @content.clone : @content.in_section(section)
655
668
  end
656
669
 
657
670
  opt[:time_filter] = [nil, nil]
@@ -798,6 +811,8 @@ module Doing
798
811
  output.concat(filtered_items.reverse.slice(0, count))
799
812
  end
800
813
 
814
+ logger.benchmark(:filter_items, :finish)
815
+
801
816
  output
802
817
  end
803
818
 
@@ -847,7 +862,7 @@ module Doing
847
862
  note.map!(&:strip)
848
863
  note.delete_if(&:ignore?)
849
864
  item = items[i]
850
- old_item = item.dup
865
+ old_item = item.clone
851
866
  item.date = date || items[i].date
852
867
  item.title = title
853
868
  item.note = note
@@ -855,7 +870,7 @@ module Doing
855
870
  Doing.logger.count(:skipped, level: :debug)
856
871
  else
857
872
  Doing.logger.count(:updated)
858
- Hooks.trigger :post_entry_updated, self, item
873
+ Hooks.trigger :post_entry_updated, self, item, old_item
859
874
  end
860
875
  end
861
876
  end
@@ -1045,9 +1060,10 @@ module Doing
1045
1060
  else
1046
1061
  opt[:resume]
1047
1062
  end
1063
+ old_item = item.clone
1048
1064
  new_entry = reset_item(item, date: date, resume: res)
1049
1065
  @content.update_item(item, new_entry)
1050
- Hooks.trigger :post_entry_updated, self, new_entry
1066
+ Hooks.trigger :post_entry_updated, self, new_entry, old_item
1051
1067
  end
1052
1068
  write(@doing_file)
1053
1069
 
@@ -1062,8 +1078,9 @@ module Doing
1062
1078
  if opt[:flag]
1063
1079
  tag = @config['marker_tag'] || 'flagged'
1064
1080
  items.map! do |i|
1081
+ old_item = i.clone
1065
1082
  i.tag(tag, date: false, remove: opt[:remove], single: single)
1066
- Hooks.trigger :post_entry_updated, self, i
1083
+ Hooks.trigger :post_entry_updated, self, i, old_item
1067
1084
  end
1068
1085
  end
1069
1086
 
@@ -1071,9 +1088,10 @@ module Doing
1071
1088
  tag = 'done'
1072
1089
  items.map! do |i|
1073
1090
  if i.should_finish?
1091
+ old_item = i.clone
1074
1092
  should_date = !opt[:cancel] && i.should_time?
1075
1093
  i.tag(tag, date: should_date, remove: opt[:remove], single: single)
1076
- Hooks.trigger :post_entry_updated, self, i
1094
+ Hooks.trigger :post_entry_updated, self, i, old_item
1077
1095
  end
1078
1096
  end
1079
1097
  end
@@ -1087,8 +1105,9 @@ module Doing
1087
1105
  else
1088
1106
  logger.count(:added_tags)
1089
1107
  logger.write(items.count == 1 ? :info : :debug, 'Tagged:', new_title)
1108
+ old_item = i.clone
1090
1109
  i.title = new_title
1091
- Hooks.trigger :post_entry_updated, self, i
1110
+ Hooks.trigger :post_entry_updated, self, i, old_item
1092
1111
  end
1093
1112
  end
1094
1113
  end
@@ -1096,17 +1115,19 @@ module Doing
1096
1115
  if opt[:tag]
1097
1116
  tag = opt[:tag]
1098
1117
  items.map! do |i|
1118
+ old_item = i.clone
1099
1119
  i.tag(tag, date: false, remove: opt[:remove], single: single)
1100
1120
  i.expand_date_tags(@config['date_tags'])
1101
- Hooks.trigger :post_entry_updated, self, i
1121
+ Hooks.trigger :post_entry_updated, self, i, old_item
1102
1122
  end
1103
1123
  end
1104
1124
 
1105
1125
  if opt[:archive] || opt[:move]
1106
1126
  section = opt[:archive] ? 'Archive' : guess_section(opt[:move])
1107
1127
  items.map! do |i|
1128
+ old_item = i.clone
1108
1129
  i.move_to(section, label: true)
1109
- Hooks.trigger :post_entry_updated, self, i
1130
+ Hooks.trigger :post_entry_updated, self, i, old_item
1110
1131
  end
1111
1132
  end
1112
1133
 
@@ -1193,6 +1214,7 @@ module Doing
1193
1214
  opt[:sequential] ||= false
1194
1215
  opt[:date] ||= false
1195
1216
  opt[:remove] ||= false
1217
+ opt[:update] ||= false
1196
1218
  opt[:autotag] ||= false
1197
1219
  opt[:back] ||= false
1198
1220
  opt[:unfinished] ||= false
@@ -1228,6 +1250,7 @@ module Doing
1228
1250
  end
1229
1251
 
1230
1252
  items.each do |item|
1253
+ old_item = item.clone
1231
1254
  added = []
1232
1255
  removed = []
1233
1256
 
@@ -1304,7 +1327,7 @@ module Doing
1304
1327
  else
1305
1328
  old_title = item.title.dup
1306
1329
  should_date = opt[:date] && item.should_time?
1307
- item.title.tag!('done', remove: true) if tag =~ /done/ && !should_date
1330
+ item.title.tag!('done', remove: true) if tag =~ /done/ && (!should_date || opt[:update])
1308
1331
  item.title.tag!(tag, value: should_date ? done_date.strftime('%F %R') : nil)
1309
1332
  added << tag if old_title != item.title
1310
1333
  end
@@ -1322,7 +1345,7 @@ module Doing
1322
1345
  end
1323
1346
 
1324
1347
  item.expand_date_tags(@config['date_tags'])
1325
- Hooks.trigger :post_entry_updated, self, item
1348
+ Hooks.trigger :post_entry_updated, self, item, old_item
1326
1349
  end
1327
1350
 
1328
1351
  write(@doing_file)
@@ -1361,6 +1384,7 @@ module Doing
1361
1384
  return
1362
1385
  end
1363
1386
 
1387
+ old_item = item.clone
1364
1388
  content = ["#{item.date.strftime('%F %R')} | #{item.title.dup}"]
1365
1389
  content << item.note.strip_lines.join("\n") unless item.note.empty?
1366
1390
  new_item = fork_editor(content.join("\n"))
@@ -1376,7 +1400,7 @@ module Doing
1376
1400
  item.title = title
1377
1401
  item.note.add(note, replace: true)
1378
1402
  logger.info('Edited:', item.title)
1379
- Hooks.trigger :post_entry_updated, self, item.dup
1403
+ Hooks.trigger :post_entry_updated, self, item, old_item
1380
1404
 
1381
1405
  write(@doing_file)
1382
1406
  end
@@ -1413,6 +1437,7 @@ module Doing
1413
1437
  found_items = 0
1414
1438
 
1415
1439
  @content.each_with_index do |item, i|
1440
+ old_item = i.clone
1416
1441
  next unless item.section == opt[:section] || opt[:section] =~ /all/i
1417
1442
 
1418
1443
  next unless item.title =~ /@#{tag}/
@@ -1431,7 +1456,7 @@ module Doing
1431
1456
  logger.count(:completed)
1432
1457
  logger.info('Completed:', item.title)
1433
1458
  end
1434
- Hooks.trigger :post_entry_updated, self, item
1459
+ Hooks.trigger :post_entry_updated, self, item, old_item
1435
1460
  end
1436
1461
 
1437
1462
 
@@ -1492,7 +1517,7 @@ module Doing
1492
1517
 
1493
1518
  unless ((!tags.empty? && !item.tags?(tags, bool)) || (opt[:search] && !item.search(opt[:search].to_s)) || (opt[:before] && item.date >= cutoff))
1494
1519
  new_item = @content.delete(item)
1495
- Hooks.trigger :post_entry_removed, self, item.dup
1520
+ Hooks.trigger :post_entry_removed, self, item.clone
1496
1521
  raise DoingRuntimeError, "Error deleting item: #{item}" if new_item.nil?
1497
1522
 
1498
1523
  new_content.add_section(new_item.section, log: false)
@@ -1598,6 +1623,7 @@ module Doing
1598
1623
  ## @param opt [Hash] Additional Options
1599
1624
  ##
1600
1625
  def list_section(opt, items: Items.new)
1626
+ logger.benchmark(:list_section, :start)
1601
1627
  opt[:config_template] ||= 'default'
1602
1628
 
1603
1629
  tpl_cfg = @config.dig('templates', opt[:config_template])
@@ -1611,7 +1637,7 @@ module Doing
1611
1637
  cfg.deep_merge({
1612
1638
  'wrap_width' => @config['wrap_width'] || 0,
1613
1639
  'date_format' => @config['default_date_format'],
1614
- 'order' => @config['order'] || 'asc',
1640
+ 'order' => @config['order'] || :asc,
1615
1641
  'tags_color' => @config['tags_color'],
1616
1642
  'duration' => @config['duration'],
1617
1643
  'interval_format' => @config['interval_format']
@@ -1623,8 +1649,8 @@ module Doing
1623
1649
  opt[:age] ||= :newest
1624
1650
  opt[:age] = opt[:age].normalize_age
1625
1651
  opt[:format] ||= cfg['date_format']
1626
- opt[:order] ||= cfg['order'] || 'asc'
1627
- opt[:tag_order] ||= 'asc'
1652
+ opt[:order] ||= cfg['order'] || :asc
1653
+ opt[:tag_order] ||= :asc
1628
1654
  opt[:tags_color] = cfg['tags_color'] || false if opt[:tags_color].nil?
1629
1655
  opt[:template] ||= cfg['template']
1630
1656
 
@@ -1650,7 +1676,7 @@ module Doing
1650
1676
 
1651
1677
  items = filter_items(items, opt: opt)
1652
1678
 
1653
- items.reverse! unless opt[:order] =~ /^d/i
1679
+ items.reverse! unless opt[:order].normalize_order == :desc
1654
1680
 
1655
1681
  if opt[:delete]
1656
1682
  delete_items(items, force: opt[:force])
@@ -1673,6 +1699,7 @@ module Doing
1673
1699
  opt[:output] ||= 'template'
1674
1700
  opt[:wrap_width] ||= @config['templates']['default']['wrap_width'] || 0
1675
1701
 
1702
+ logger.benchmark(:list_section, :finish)
1676
1703
  output(items, title, is_single, opt)
1677
1704
  end
1678
1705
 
@@ -1700,7 +1727,7 @@ module Doing
1700
1727
  destination = guess_section(destination)
1701
1728
 
1702
1729
  if @content.section?(destination) && (@content.section?(section) || archive_all)
1703
- do_archive(section, destination, { count: count, tags: tags, bool: bool, search: options[:search], label: options[:label], before: options[:before] })
1730
+ do_archive(section, destination, { count: count, tags: tags, bool: bool, search: options[:search], label: options[:label], before: options[:before], after: options[:after], from: options[:from] })
1704
1731
  write(doing_file)
1705
1732
  else
1706
1733
  raise InvalidArgument, 'Either source or destination does not exist'
@@ -1722,7 +1749,7 @@ module Doing
1722
1749
  cfg = @config['templates'][opt[:config_template]].deep_merge(@config['templates']['default'], { extend_existing_arrays: true, sort_merged_arrays: true }).deep_merge({
1723
1750
  'wrap_width' => @config['wrap_width'] || 0,
1724
1751
  'date_format' => @config['default_date_format'],
1725
- 'order' => @config['order'] || 'asc',
1752
+ 'order' => @config['order'] || :asc,
1726
1753
  'tags_color' => @config['tags_color'],
1727
1754
  'duration' => @config['duration'],
1728
1755
  'interval_format' => @config['interval_format']
@@ -1741,7 +1768,7 @@ module Doing
1741
1768
  from: opt[:from],
1742
1769
  format: cfg['date_format'],
1743
1770
  interval_format: opt[:interval_format],
1744
- order: cfg['order'] || 'asc',
1771
+ order: cfg['order'] || :asc,
1745
1772
  output: output,
1746
1773
  section: opt[:section],
1747
1774
  sort_tags: opt[:sort_tags],
@@ -1776,7 +1803,7 @@ module Doing
1776
1803
  list_section({
1777
1804
  section: section,
1778
1805
  count: 0,
1779
- order: 'asc',
1806
+ order: :asc,
1780
1807
  date_filter: dates,
1781
1808
  times: times,
1782
1809
  output: output,
@@ -1842,7 +1869,7 @@ module Doing
1842
1869
  cfg = @config['templates'][opt[:config_template]].deep_merge(@config['templates']['default'], { extend_existing_arrays: true, sort_merged_arrays: true }).deep_merge({
1843
1870
  'wrap_width' => @config['wrap_width'] || 0,
1844
1871
  'date_format' => @config['default_date_format'],
1845
- 'order' => @config['order'] || 'asc',
1872
+ 'order' => @config['order'] || :asc,
1846
1873
  'tags_color' => @config['tags_color'],
1847
1874
  'duration' => @config['duration'],
1848
1875
  'interval_format' => @config['interval_format']
@@ -1858,7 +1885,7 @@ module Doing
1858
1885
  opt[:count] = count
1859
1886
  opt[:format] = cfg['date_format']
1860
1887
  opt[:template] = opt[:template] || cfg['template']
1861
- opt[:order] = 'asc'
1888
+ opt[:order] = :asc
1862
1889
  opt[:times] = times
1863
1890
 
1864
1891
  list_section(opt)
@@ -1875,7 +1902,7 @@ module Doing
1875
1902
  cfg = @config['templates'][options[:config_template]].deep_merge(@config['templates']['default'], { extend_existing_arrays: true, sort_merged_arrays: true }).deep_merge({
1876
1903
  'wrap_width' => @config['wrap_width'] || 0,
1877
1904
  'date_format' => @config['default_date_format'],
1878
- 'order' => @config['order'] || 'asc',
1905
+ 'order' => @config['order'] || :asc,
1879
1906
  'tags_color' => @config['tags_color'],
1880
1907
  'duration' => @config['duration'],
1881
1908
  'interval_format' => @config['interval_format']
@@ -2022,10 +2049,10 @@ module Doing
2022
2049
  ##
2023
2050
  ## @param format [String] return format (html,
2024
2051
  ## json, or text)
2025
- ## @param sort_by_name [Boolean] Sort by name if true, otherwise by time
2026
- ## @param sort_order [String] The sort order (asc or desc)
2052
+ ## @param sort_by [Symbol] Sort by :name or :time
2053
+ ## @param sort_order [Symbol] The sort order (:asc or :desc)
2027
2054
  ##
2028
- def tag_times(format: :text, sort_by_name: false, sort_order: 'asc')
2055
+ def tag_times(format: :text, sort_by: :time, sort_order: :asc)
2029
2056
  return '' if @timers.empty?
2030
2057
 
2031
2058
  max = @timers.keys.sort_by { |k| k.length }.reverse[0].length + 1
@@ -2033,13 +2060,13 @@ module Doing
2033
2060
  total = @timers.delete('All')
2034
2061
 
2035
2062
  tags_data = @timers.delete_if { |_k, v| v == 0 }
2036
- sorted_tags_data = if sort_by_name
2063
+ sorted_tags_data = if sort_by.normalize_tag_sort == :name
2037
2064
  tags_data.sort_by { |k, _v| k }
2038
2065
  else
2039
2066
  tags_data.sort_by { |_k, v| v }
2040
2067
  end
2041
2068
 
2042
- sorted_tags_data.reverse! if sort_order =~ /^asc/i
2069
+ sorted_tags_data.reverse! if sort_order.normalize_order == :asc
2043
2070
  case format
2044
2071
  when :html
2045
2072
 
@@ -2189,9 +2216,9 @@ EOS
2189
2216
  Doing.config_with(ENV['DOING_CONFIG'], { ignore_local: true })
2190
2217
  end
2191
2218
 
2192
- Doing.logger.benchmark(:configure, :start)
2219
+ logger.benchmark(:configure, :start)
2193
2220
  config = Doing.config
2194
- Doing.logger.benchmark(:configure, :finish)
2221
+ logger.benchmark(:configure, :finish)
2195
2222
 
2196
2223
  config.settings['backup_dir'] = ENV['DOING_BACKUP_DIR'] if ENV['DOING_BACKUP_DIR']
2197
2224
  @config = config.settings
@@ -2202,7 +2229,7 @@ EOS
2202
2229
 
2203
2230
  filename ||= @config['doing_file']
2204
2231
  init_doing_file(filename)
2205
- current_content = @content.dup
2232
+ current_content = @content.clone
2206
2233
  backup_file = Util::Backup.last_backup(filename, count: 1)
2207
2234
  raise DoingRuntimeError, 'No undo history to diff' if backup_file.nil?
2208
2235
 
@@ -2245,6 +2272,7 @@ EOS
2245
2272
  ## template trigger
2246
2273
  ##
2247
2274
  def output(items, title, is_single, opt)
2275
+ logger.benchmark(:output, :start)
2248
2276
  opt ||= {}
2249
2277
  out = nil
2250
2278
 
@@ -2262,7 +2290,7 @@ EOS
2262
2290
  end
2263
2291
 
2264
2292
  logger.debug('Output:', "#{items.count} #{items.count == 1 ? 'item' : 'items'} shown")
2265
-
2293
+ logger.benchmark(:output, :finish)
2266
2294
  out
2267
2295
  end
2268
2296
 
@@ -2306,25 +2334,37 @@ EOS
2306
2334
  section_items = @content.in_section(section)
2307
2335
  max = section_items.count - count.to_i
2308
2336
 
2337
+ opt[:after] = opt[:from][0] if opt[:from]
2338
+ opt[:before] = opt[:from][1] if opt[:from]
2339
+
2340
+ time_rx = /^(\d{1,2}+(:\d{1,2}+)?( *(am|pm))?|midnight|noon)$/
2341
+
2342
+ if opt[:before].is_a?(String) && opt[:before] =~ time_rx
2343
+ opt[:before] = opt[:before].chronify(guess: :end, future: false)
2344
+ end
2345
+
2346
+ if opt[:after].is_a?(String) && opt[:after] =~ time_rx
2347
+ opt[:after] = opt[:after].chronify(guess: :begin, future: false)
2348
+ end
2349
+
2309
2350
  counter = 0
2310
2351
 
2311
2352
  @content.map do |item|
2312
2353
  break if counter >= max
2313
- if opt[:before]
2314
- time_string = opt[:before]
2315
- cutoff = time_string.chronify(guess: :begin)
2316
- end
2317
2354
 
2318
- if (item.section.downcase != section.downcase && section != /^all$/i) || item.section.downcase == destination.downcase
2319
- item
2320
- elsif ((!tags.empty? && !item.tags?(tags, bool)) || (opt[:search] && !item.search(opt[:search].to_s)) || (opt[:before] && item.date >= cutoff))
2321
- item
2322
- else
2323
- counter += 1
2324
- item.move_to(destination, label: label, log: false)
2325
- Hooks.trigger :post_entry_updated, self, item.dup
2326
- item
2327
- end
2355
+ next if item.section.downcase == destination.downcase
2356
+
2357
+ next if item.section.downcase != section.downcase && section != /^all$/i
2358
+
2359
+ next if (opt[:before] && item.date > opt[:before]) || (opt[:after] && item.date < opt[:after])
2360
+
2361
+ next if (!tags.empty? && !item.tags?(tags, bool)) || (opt[:search] && !item.search(opt[:search].to_s))
2362
+
2363
+ counter += 1
2364
+ old_item = item.clone
2365
+ item.move_to(destination, label: label, log: false)
2366
+ Hooks.trigger :post_entry_updated, self, item, old_item
2367
+ item
2328
2368
  end
2329
2369
 
2330
2370
  if counter.positive?
data/lib/doing.rb CHANGED
@@ -28,10 +28,11 @@ require_relative 'doing/hash'
28
28
  require_relative 'doing/types'
29
29
  require_relative 'doing/colors'
30
30
  require_relative 'doing/template_string'
31
- require_relative 'doing/string'
31
+ require_relative 'doing/string/string'
32
32
  require_relative 'doing/time'
33
- require_relative 'doing/array'
34
- require_relative 'doing/symbol'
33
+ require_relative 'doing/array/array'
34
+ require_relative 'doing/good'
35
+ require_relative 'doing/normalize'
35
36
  require_relative 'doing/util'
36
37
  require_relative 'doing/util_backup'
37
38
  require_relative 'doing/configuration'
@@ -49,9 +50,7 @@ require_relative 'doing/pager'
49
50
  require_relative 'doing/completion'
50
51
  require_relative 'doing/boolean_term_parser'
51
52
  require_relative 'doing/phrase_parser'
52
- require_relative 'doing/array_chronify'
53
- require_relative 'doing/numeric_chronify'
54
- require_relative 'doing/string_chronify'
53
+ require_relative 'doing/chronify/chronify'
55
54
  # require 'doing/markdown_document_listener'
56
55
 
57
56
  # Main doing module
@@ -36,8 +36,7 @@ command :wiki do |c|
36
36
  c.switch [:only_timed], default_value: false, negatable: false
37
37
 
38
38
  c.action do |global, options, args|
39
- wwid = global[:wwid]
40
- tags = wwid.tag_groups([], opt: options)
39
+ tags = @wwid.tag_groups([], opt: options)
41
40
 
42
41
  wiki = Doing::Plugins.plugins.dig(:export, 'wiki', :class)
43
42
 
@@ -46,7 +45,7 @@ command :wiki do |c|
46
45
 
47
46
  raise RuntimeError, 'Missing plugin "wiki"' unless wiki
48
47
 
49
- out = wiki.render(wwid, items, variables: export_options)
48
+ out = wiki.render(@wwid, items, variables: export_options)
50
49
 
51
50
  if out
52
51
  FileUtils.mkdir_p('doing_wiki')
@@ -56,13 +55,13 @@ command :wiki do |c|
56
55
  end
57
56
  end
58
57
 
59
- template = if wwid.config['export_templates']['wiki_index'] && File.exist?(File.expand_path(wwid.config['export_templates']['wiki_index']))
60
- IO.read(File.expand_path(wwid.config['export_templates']['wiki_index']))
58
+ template = if @settings['export_templates']['wiki_index'] && File.exist?(File.expand_path(@settings['export_templates']['wiki_index']))
59
+ IO.read(File.expand_path(@settings['export_templates']['wiki_index']))
61
60
  else
62
61
  wiki.template('wiki_index')
63
62
  end
64
- style = if wwid.config['export_templates']['wiki_css'] && File.exist?(File.expand_path(wwid.config['export_templates']['wiki_css']))
65
- IO.read(File.expand_path(wwid.config['export_templates']['wiki_css']))
63
+ style = if @settings['export_templates']['wiki_css'] && File.exist?(File.expand_path(@settings['export_templates']['wiki_css']))
64
+ IO.read(File.expand_path(@settings['export_templates']['wiki_css']))
66
65
  else
67
66
  wiki.template('wiki_css')
68
67
  end
@@ -74,7 +74,7 @@ module Doing
74
74
  self.template('wiki_css')
75
75
  end
76
76
 
77
- totals = opt[:totals] ? wwid.tag_times(format: :html, sort_by_name: opt[:sort_tags], sort_order: opt[:tag_order]) : ''
77
+ totals = opt[:totals] ? wwid.tag_times(format: :html, sort_by: opt[:sort_tags], sort_order: opt[:tag_order]) : ''
78
78
  engine = Haml::Engine.new(template)
79
79
  Doing.logger.debug('Wiki Export:', "#{items_out.count} items output to #{variables[:page_title]} wiki page")
80
80
  @out = engine.render(Object.new,