doing 2.1.42 → 2.1.43

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 (137) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +1 -1
  5. data/bin/commands/changes.rb +11 -1
  6. data/bin/commands/flag.rb +1 -1
  7. data/bin/commands/grep.rb +3 -1
  8. data/bin/commands/last.rb +2 -0
  9. data/bin/commands/on.rb +8 -1
  10. data/bin/commands/recent.rb +3 -1
  11. data/bin/commands/show.rb +3 -0
  12. data/bin/commands/since.rb +2 -1
  13. data/bin/commands/template.rb +14 -25
  14. data/bin/commands/today.rb +3 -1
  15. data/bin/commands/view.rb +36 -73
  16. data/bin/commands/views.rb +40 -4
  17. data/bin/commands/yesterday.rb +3 -1
  18. data/bin/doing +7 -3
  19. data/docs/doc/Array.html +1 -1
  20. data/docs/doc/BooleanTermParser/Clause.html +1 -1
  21. data/docs/doc/BooleanTermParser/Operator.html +1 -1
  22. data/docs/doc/BooleanTermParser/Query.html +1 -1
  23. data/docs/doc/BooleanTermParser/QueryParser.html +1 -1
  24. data/docs/doc/BooleanTermParser/QueryTransformer.html +1 -1
  25. data/docs/doc/BooleanTermParser.html +1 -1
  26. data/docs/doc/Doing/ArrayCleanup.html +316 -0
  27. data/docs/doc/Doing/ArrayNestedHash.html +1 -1
  28. data/docs/doc/Doing/ArrayTags.html +1 -1
  29. data/docs/doc/Doing/CSVExport.html +1 -1
  30. data/docs/doc/Doing/CalendarImport.html +1 -1
  31. data/docs/doc/Doing/Change.html +74 -3
  32. data/docs/doc/Doing/Changes.html +3 -3
  33. data/docs/doc/Doing/ChronifyArray.html +1 -1
  34. data/docs/doc/Doing/ChronifyNumeric.html +1 -1
  35. data/docs/doc/Doing/ChronifyString.html +1 -1
  36. data/docs/doc/Doing/Color.html +1 -1
  37. data/docs/doc/Doing/Completion/BashCompletions.html +1 -1
  38. data/docs/doc/Doing/Completion/FishCompletions.html +1 -1
  39. data/docs/doc/Doing/Completion/StringUtils.html +1 -1
  40. data/docs/doc/Doing/Completion/ZshCompletions.html +1 -1
  41. data/docs/doc/Doing/Completion.html +1 -1
  42. data/docs/doc/Doing/Configuration.html +80 -1
  43. data/docs/doc/Doing/DayOneRenderer.html +1 -1
  44. data/docs/doc/Doing/DayoneExport.html +1 -1
  45. data/docs/doc/Doing/DoingImport.html +1 -1
  46. data/docs/doc/Doing/Entry.html +109 -4
  47. data/docs/doc/Doing/Errors/DoingNoTraceError.html +1 -1
  48. data/docs/doc/Doing/Errors/DoingRuntimeError.html +1 -1
  49. data/docs/doc/Doing/Errors/DoingStandardError.html +1 -1
  50. data/docs/doc/Doing/Errors/EmptyInput.html +1 -1
  51. data/docs/doc/Doing/Errors/HistoryLimitError.html +1 -1
  52. data/docs/doc/Doing/Errors/InvalidPlugin.html +1 -1
  53. data/docs/doc/Doing/Errors/MissingBackupFile.html +1 -1
  54. data/docs/doc/Doing/Errors/NoResults.html +1 -1
  55. data/docs/doc/Doing/Errors/PluginException.html +1 -1
  56. data/docs/doc/Doing/Errors/UserCancelled.html +1 -1
  57. data/docs/doc/Doing/Errors/WrongCommand.html +1 -1
  58. data/docs/doc/Doing/Errors.html +1 -1
  59. data/docs/doc/Doing/HTMLExport.html +1 -1
  60. data/docs/doc/Doing/Hooks.html +1 -1
  61. data/docs/doc/Doing/Item.html +1 -1
  62. data/docs/doc/Doing/ItemDates.html +1 -1
  63. data/docs/doc/Doing/ItemQuery.html +1 -1
  64. data/docs/doc/Doing/ItemState.html +1 -1
  65. data/docs/doc/Doing/ItemTags.html +1 -1
  66. data/docs/doc/Doing/Items.html +1 -1
  67. data/docs/doc/Doing/JSONExport.html +1 -1
  68. data/docs/doc/Doing/Logger.html +1 -1
  69. data/docs/doc/Doing/MarkdownExport.html +1 -1
  70. data/docs/doc/Doing/Note.html +1 -1
  71. data/docs/doc/Doing/Pager.html +1 -1
  72. data/docs/doc/Doing/Plugins.html +1 -1
  73. data/docs/doc/Doing/Prompt.html +1 -1
  74. data/docs/doc/Doing/PromptChoose.html +1 -1
  75. data/docs/doc/Doing/PromptFZF.html +1 -1
  76. data/docs/doc/Doing/PromptInput.html +1 -1
  77. data/docs/doc/Doing/PromptSTD.html +1 -1
  78. data/docs/doc/Doing/PromptYN.html +1 -1
  79. data/docs/doc/Doing/Section.html +1 -1
  80. data/docs/doc/Doing/StringHighlight.html +1 -1
  81. data/docs/doc/Doing/StringNormalize.html +35 -1
  82. data/docs/doc/Doing/StringQuery.html +1 -1
  83. data/docs/doc/Doing/StringTags.html +1 -1
  84. data/docs/doc/Doing/StringTransform.html +1 -1
  85. data/docs/doc/Doing/StringTruncate.html +1 -1
  86. data/docs/doc/Doing/StringURL.html +1 -1
  87. data/docs/doc/Doing/SymbolNormalize.html +1 -1
  88. data/docs/doc/Doing/TaskPaperExport.html +1 -1
  89. data/docs/doc/Doing/TemplateExport.html +1 -1
  90. data/docs/doc/Doing/TemplateString.html +2 -2
  91. data/docs/doc/Doing/TimingImport.html +1 -1
  92. data/docs/doc/Doing/Types.html +1 -1
  93. data/docs/doc/Doing/Util/Backup.html +1 -1
  94. data/docs/doc/Doing/Util.html +1 -1
  95. data/docs/doc/Doing/Version.html +1 -1
  96. data/docs/doc/Doing/WWID.html +71 -3
  97. data/docs/doc/Doing.html +2 -2
  98. data/docs/doc/FalseClass.html +1 -1
  99. data/docs/doc/GLI/Commands/Help.html +1 -1
  100. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
  101. data/docs/doc/GLI/Commands.html +1 -1
  102. data/docs/doc/GLI.html +1 -1
  103. data/docs/doc/Hash.html +461 -6
  104. data/docs/doc/Numeric.html +1 -1
  105. data/docs/doc/Object.html +1 -1
  106. data/docs/doc/PhraseParser/Operator.html +1 -1
  107. data/docs/doc/PhraseParser/PhraseClause.html +1 -1
  108. data/docs/doc/PhraseParser/Query.html +1 -1
  109. data/docs/doc/PhraseParser/QueryParser.html +1 -1
  110. data/docs/doc/PhraseParser/QueryTransformer.html +1 -1
  111. data/docs/doc/PhraseParser/TermClause.html +1 -1
  112. data/docs/doc/PhraseParser.html +1 -1
  113. data/docs/doc/Status.html +1 -1
  114. data/docs/doc/String.html +2 -2
  115. data/docs/doc/Symbol.html +1 -1
  116. data/docs/doc/Time.html +1 -1
  117. data/docs/doc/TrueClass.html +1 -1
  118. data/docs/doc/_index.html +1 -1
  119. data/docs/doc/file.README.html +2 -2
  120. data/docs/doc/index.html +2 -2
  121. data/docs/doc/method_list.html +484 -388
  122. data/docs/doc/top-level-namespace.html +3 -1
  123. data/doing.rdoc +101 -6
  124. data/lib/completion/_doing.zsh +13 -13
  125. data/lib/completion/doing.bash +22 -22
  126. data/lib/completion/doing.fish +15 -1
  127. data/lib/doing/add_options.rb +35 -0
  128. data/lib/doing/changelog/change.rb +13 -5
  129. data/lib/doing/changelog/changes.rb +11 -2
  130. data/lib/doing/changelog/entry.rb +9 -2
  131. data/lib/doing/configuration.rb +17 -0
  132. data/lib/doing/hash.rb +126 -22
  133. data/lib/doing/normalize.rb +13 -0
  134. data/lib/doing/pager.rb +1 -1
  135. data/lib/doing/version.rb +1 -1
  136. data/lib/doing/wwid/wwid.rb +21 -3
  137. metadata +3 -2
@@ -228,6 +228,8 @@ complete -c doing -l all -s a -f -n '__fish_doing_using_command changes changel
228
228
  complete -c doing -l interactive -s i -f -n '__fish_doing_using_command changes changelog' -d Open\ changelog\ in\ interactive\ viewer
229
229
  complete -c doing -l lookup -s l -f -r -n '__fish_doing_using_command changes changelog' -d Look\ up\ a\ specific\ version
230
230
  complete -c doing -l markdown -f -n '__fish_doing_using_command changes changelog' -d Output\ raw\ Markdown
231
+ complete -c doing -l only -f -r -n '__fish_doing_using_command changes changelog' -d Only\ show\ changes\ of\ type\(s\)
232
+ complete -c doing -l prefix -s p -f -n '__fish_doing_using_command changes changelog' -d Include
231
233
  complete -c doing -l render -f -n '__fish_doing_using_command changes changelog' -d Force\ rendered\ output
232
234
  complete -c doing -l search -s s -f -r -n '__fish_doing_using_command changes changelog' -d Show\ changelogs\ matching\ search\ terms
233
235
  complete -c doing -l sort -f -r -n '__fish_doing_using_command changes changelog' -d Sort\ order
@@ -281,6 +283,7 @@ complete -c doing -l not -f -n '__fish_doing_using_command grep search' -d Sea
281
283
  complete -c doing -l output -s o -f -r -n '__fish_doing_using_command grep search' -d Output\ to\ export\ format
282
284
  complete -c doing -l only_timed -f -n '__fish_doing_using_command grep search' -d Only\ show\ items\ with\ recorded\ time\ intervals
283
285
  complete -c doing -l section -s s -f -r -n '__fish_doing_using_command grep search' -d Section
286
+ complete -c doing -l save -f -r -n '__fish_doing_using_command grep search' -d Save\ all\ current\ command\ line\ options\ as\ a\ new\ view
284
287
  complete -c doing -l times -s t -f -n '__fish_doing_using_command grep search' -d Show\ time\ intervals\ on\ @done\ tasks
285
288
  complete -c doing -l tag -f -r -n '__fish_doing_using_command grep search' -d Filter\ entries\ by\ tag
286
289
  complete -c doing -l tag_order -f -r -n '__fish_doing_using_command grep search' -d Tag\ sort\ direction
@@ -314,6 +317,7 @@ complete -c doing -l hilite -s h -f -n '__fish_doing_using_command last' -d Hig
314
317
  complete -c doing -l not -f -n '__fish_doing_using_command last' -d Show\ items\ that\ \*don\'t\*\ match\ search/tag\ filters
315
318
  complete -c doing -l output -s o -f -r -n '__fish_doing_using_command last' -d Output\ to\ export\ format
316
319
  complete -c doing -l section -s s -f -r -n '__fish_doing_using_command last' -d Specify\ a\ section
320
+ complete -c doing -l save -f -r -n '__fish_doing_using_command last' -d Save\ all\ current\ command\ line\ options\ as\ a\ new\ view
317
321
  complete -c doing -l search -f -r -n '__fish_doing_using_command last' -d Filter\ entries\ using\ a\ search\ query
318
322
  complete -c doing -l tag -f -r -n '__fish_doing_using_command last' -d Filter\ entries\ by\ tag
319
323
  complete -c doing -l template -f -r -n '__fish_doing_using_command last' -d Override\ output\ format\ with\ a\ template\ string\ containing\ \%placeholders
@@ -371,6 +375,7 @@ complete -c doing -l not -f -n '__fish_doing_using_command on' -d Show\ items\
371
375
  complete -c doing -l output -s o -f -r -n '__fish_doing_using_command on' -d Output\ to\ export\ format
372
376
  complete -c doing -l only_timed -f -n '__fish_doing_using_command on' -d Only\ show\ items\ with\ recorded\ time\ intervals
373
377
  complete -c doing -l section -s s -f -r -n '__fish_doing_using_command on' -d Section
378
+ complete -c doing -l save -f -r -n '__fish_doing_using_command on' -d Save\ all\ current\ command\ line\ options\ as\ a\ new\ view
374
379
  complete -c doing -l search -f -r -n '__fish_doing_using_command on' -d Filter\ entries\ using\ a\ search\ query
375
380
  complete -c doing -l times -s t -f -n '__fish_doing_using_command on' -d Show\ time\ intervals\ on\ @done\ tasks
376
381
  complete -c doing -l tag -f -r -n '__fish_doing_using_command on' -d Filter\ entries\ by\ tag
@@ -391,6 +396,7 @@ complete -c doing -l interactive -s i -f -n '__fish_doing_using_command recent'
391
396
  complete -c doing -l output -s o -f -r -n '__fish_doing_using_command recent' -d Output\ to\ export\ format
392
397
  complete -c doing -l only_timed -f -n '__fish_doing_using_command recent' -d Only\ show\ items\ with\ recorded\ time\ intervals
393
398
  complete -c doing -l section -s s -f -r -n '__fish_doing_using_command recent' -d Section
399
+ complete -c doing -l save -f -r -n '__fish_doing_using_command recent' -d Save\ all\ current\ command\ line\ options\ as\ a\ new\ view
394
400
  complete -c doing -l times -s t -f -n '__fish_doing_using_command recent' -d Show\ time\ intervals\ on\ @done\ tasks
395
401
  complete -c doing -l tag_order -f -r -n '__fish_doing_using_command recent' -d Tag\ sort\ direction
396
402
  complete -c doing -l tag_sort -f -r -n '__fish_doing_using_command recent' -d Sort\ tags\ by
@@ -461,6 +467,7 @@ complete -c doing -l not -f -n '__fish_doing_using_command show' -d Show\ item
461
467
  complete -c doing -l output -s o -f -r -n '__fish_doing_using_command show' -d Output\ to\ export\ format
462
468
  complete -c doing -l only_timed -f -n '__fish_doing_using_command show' -d Only\ show\ items\ with\ recorded\ time\ intervals
463
469
  complete -c doing -l sort -s s -f -r -n '__fish_doing_using_command show' -d Sort\ order
470
+ complete -c doing -l save -f -r -n '__fish_doing_using_command show' -d Save\ all\ current\ command\ line\ options\ as\ a\ new\ view
464
471
  complete -c doing -l search -f -r -n '__fish_doing_using_command show' -d Filter\ entries\ using\ a\ search\ query
465
472
  complete -c doing -l times -s t -f -n '__fish_doing_using_command show' -d Show\ time\ intervals\ on\ @done\ tasks
466
473
  complete -c doing -l tag -f -r -n '__fish_doing_using_command show' -d Filter\ entries\ by\ tag
@@ -478,6 +485,7 @@ complete -c doing -l not -f -n '__fish_doing_using_command since' -d Since\ it
478
485
  complete -c doing -l output -s o -f -r -n '__fish_doing_using_command since' -d Output\ to\ export\ format
479
486
  complete -c doing -l only_timed -f -n '__fish_doing_using_command since' -d Only\ show\ items\ with\ recorded\ time\ intervals
480
487
  complete -c doing -l section -s s -f -r -n '__fish_doing_using_command since' -d Section
488
+ complete -c doing -l save -f -r -n '__fish_doing_using_command since' -d Save\ all\ current\ command\ line\ options\ as\ a\ new\ view
481
489
  complete -c doing -l search -f -r -n '__fish_doing_using_command since' -d Filter\ entries\ using\ a\ search\ query
482
490
  complete -c doing -l times -s t -f -n '__fish_doing_using_command since' -d Show\ time\ intervals\ on\ @done\ tasks
483
491
  complete -c doing -l tag -f -r -n '__fish_doing_using_command since' -d Filter\ entries\ by\ tag
@@ -533,6 +541,7 @@ complete -c doing -l from -f -r -n '__fish_doing_using_command today' -d Time\
533
541
  complete -c doing -l output -s o -f -r -n '__fish_doing_using_command today' -d Output\ to\ export\ format
534
542
  complete -c doing -l only_timed -f -n '__fish_doing_using_command today' -d Only\ show\ items\ with\ recorded\ time\ intervals
535
543
  complete -c doing -l section -s s -f -r -n '__fish_doing_using_command today' -d Specify\ a\ section
544
+ complete -c doing -l save -f -r -n '__fish_doing_using_command today' -d Save\ all\ current\ command\ line\ options\ as\ a\ new\ view
536
545
  complete -c doing -l times -s t -f -n '__fish_doing_using_command today' -d Show\ time\ intervals\ on\ @done\ tasks
537
546
  complete -c doing -l tag_order -f -r -n '__fish_doing_using_command today' -d Tag\ sort\ direction
538
547
  complete -c doing -l tag_sort -f -r -n '__fish_doing_using_command today' -d Sort\ tags\ by
@@ -549,6 +558,7 @@ complete -c doing -l bool -f -r -n '__fish_doing_using_command view' -d Boolean
549
558
  complete -c doing -l count -s c -f -r -n '__fish_doing_using_command view' -d Count\ to\ display
550
559
  complete -c doing -l case -f -r -n '__fish_doing_using_command view' -d Case\ sensitivity\ for\ search\ string\ matching\ \[\(c\)ase-sensitive
551
560
  complete -c doing -l color -f -n '__fish_doing_using_command view' -d Include\ colors\ in\ output
561
+ complete -c doing -l config_template -f -r -n '__fish_doing_using_command view' -d Output\ using\ a\ template\ from\ configuration
552
562
  complete -c doing -l duration -f -n '__fish_doing_using_command view' -d Show\ elapsed\ time\ on\ entries\ without\ @done\ tag
553
563
  complete -c doing -l from -f -r -n '__fish_doing_using_command view' -d Date\ range
554
564
  complete -c doing -l hilite -s h -f -n '__fish_doing_using_command view' -d Highlight\ search\ matches\ in\ output
@@ -562,10 +572,13 @@ complete -c doing -l times -s t -f -n '__fish_doing_using_command view' -d Show
562
572
  complete -c doing -l tag -f -r -n '__fish_doing_using_command view' -d Filter\ entries\ by\ tag
563
573
  complete -c doing -l tag_order -f -r -n '__fish_doing_using_command view' -d Tag\ sort\ direction
564
574
  complete -c doing -l tag_sort -f -r -n '__fish_doing_using_command view' -d Sort\ tags\ by
575
+ complete -c doing -l template -f -r -n '__fish_doing_using_command view' -d Override\ output\ format\ with\ a\ template\ string\ containing\ \%placeholders
565
576
  complete -c doing -l totals -f -n '__fish_doing_using_command view' -d Show\ intervals\ with\ totals\ at\ the\ end\ of\ output
566
577
  complete -c doing -l val -f -r -n '__fish_doing_using_command view' -d Perform\ a\ tag\ value\ query
567
578
  complete -c doing -l exact -s x -f -n '__fish_doing_using_command view' -d Force\ exact\ search\ string\ matching
568
579
  complete -c doing -l column -s c -f -n '__fish_doing_using_command views' -d List\ in\ single\ column
580
+ complete -c doing -l editor -s e -f -n '__fish_doing_using_command views' -d Open\ YAML\ for\ view\ in\ editor
581
+ complete -c doing -l output -s o -f -r -n '__fish_doing_using_command views' -d Output/edit\ view\ in\ alternative\ format
569
582
  complete -c doing -l after -f -r -n '__fish_doing_using_command wiki' -d Include\ entries\ newer\ than\ date
570
583
  complete -c doing -l bool -s b -f -r -n '__fish_doing_using_command wiki' -d Tag\ boolean
571
584
  complete -c doing -l before -f -r -n '__fish_doing_using_command wiki' -d Include\ entries\ older\ than\ date
@@ -582,12 +595,13 @@ complete -c doing -l from -f -r -n '__fish_doing_using_command yesterday' -d Ti
582
595
  complete -c doing -l output -s o -f -r -n '__fish_doing_using_command yesterday' -d Output\ to\ export\ format
583
596
  complete -c doing -l only_timed -f -n '__fish_doing_using_command yesterday' -d Only\ show\ items\ with\ recorded\ time\ intervals
584
597
  complete -c doing -l section -s s -f -r -n '__fish_doing_using_command yesterday' -d Specify\ a\ section
598
+ complete -c doing -l save -f -r -n '__fish_doing_using_command yesterday' -d Save\ all\ current\ command\ line\ options\ as\ a\ new\ view
585
599
  complete -c doing -l times -s t -f -n '__fish_doing_using_command yesterday' -d Show\ time\ intervals\ on\ @done\ tasks
586
600
  complete -c doing -l tag_order -f -r -n '__fish_doing_using_command yesterday' -d Tag\ sort\ direction
587
601
  complete -c doing -l tag_sort -f -r -n '__fish_doing_using_command yesterday' -d Sort\ tags\ by
588
602
  complete -c doing -l template -f -r -n '__fish_doing_using_command yesterday' -d Override\ output\ format\ with\ a\ template\ string\ containing\ \%placeholders
589
603
  complete -c doing -l totals -f -n '__fish_doing_using_command yesterday' -d Show\ time\ totals\ at\ the\ end\ of\ output
590
- complete -f -c doing -s o -l output -x -n '__fish_doing_using_command grep search last on recent select show since today view yesterday' -a '(__fish_doing_export_plugin)'
604
+ complete -f -c doing -s o -l output -x -n '__fish_doing_using_command grep search last on recent select show since today view views yesterday' -a '(__fish_doing_export_plugin)'
591
605
  complete -f -c doing -s b -l bool -x -n '__fish_doing_using_command again resume archive move autotag cancel finish grep search last mark flag note on reset begin rotate show since tag tags view wiki' -a 'and or not pattern'
592
606
  complete -f -c doing -l case -x -n '__fish_doing_using_command again resume archive move cancel finish grep search import last mark flag note on reset begin rotate select show since tag tags view' -a 'case-sensitive ignore smart'
593
607
  complete -f -c doing -l sort -x -n '__fish_doing_using_command changes changelog show tags' -a 'asc desc'
@@ -19,6 +19,8 @@
19
19
  ##
20
20
  ## :date_filter => --before, --after, --from
21
21
  ##
22
+ ## :save => --save
23
+ ##
22
24
  ## @param type [Symbol] The type
23
25
  ## @param cmd The GLI command to which the options will be added
24
26
  ##
@@ -47,6 +49,18 @@ def add_options(type, cmd, default_template: 'default')
47
49
  cmd.arg_name 'TEMPLATE_KEY'
48
50
  cmd.flag [:config_template], type: TemplateName, default_value: default_template
49
51
 
52
+ cmd.desc 'Override output format with a template string containing %placeholders'
53
+ cmd.arg_name 'TEMPLATE_STRING'
54
+ cmd.flag [:template]
55
+ when :output_template_no_defaults
56
+ cmd.desc "Output to export format (#{Doing::Plugins.plugin_names(type: :export)})"
57
+ cmd.arg_name 'FORMAT'
58
+ cmd.flag %i[o output]
59
+
60
+ cmd.desc "Output using a template from configuration"
61
+ cmd.arg_name 'TEMPLATE_KEY'
62
+ cmd.flag [:config_template], type: TemplateName
63
+
50
64
  cmd.desc 'Override output format with a template string containing %placeholders'
51
65
  cmd.arg_name 'TEMPLATE_STRING'
52
66
  cmd.flag [:template]
@@ -138,6 +152,23 @@ def add_options(type, cmd, default_template: 'default')
138
152
  cmd.flag [:bool], must_match: REGEX_BOOL,
139
153
  default_value: :pattern,
140
154
  type: BooleanSymbol
155
+ when :tag_filter_no_defaults
156
+ cmd.desc 'Filter entries by tag. Combine multiple tags with a comma. Wildcards allowed (*, ?)'
157
+ cmd.arg_name 'TAG'
158
+ cmd.flag [:tag], type: TagArray
159
+
160
+ cmd.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50").
161
+ May be used multiple times, combined with --bool'
162
+ cmd.arg_name 'QUERY'
163
+ cmd.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
164
+
165
+ cmd.desc "#{action} items that *don't* match search/tag filters"
166
+ cmd.switch [:not], negatable: false
167
+
168
+ cmd.desc 'Boolean used to combine multiple tags. Use PATTERN to parse + and - as booleans'
169
+ cmd.arg_name 'BOOLEAN'
170
+ cmd.flag [:bool], must_match: REGEX_BOOL,
171
+ type: BooleanSymbol
141
172
  when :time_filter
142
173
  cmd.desc 'View entries before specified time (e.g. 8am, 12:30pm, 15:00)'
143
174
  cmd.arg_name 'TIME_STRING'
@@ -186,5 +217,9 @@ def add_options(type, cmd, default_template: 'default')
186
217
  end
187
218
  cmd.arg_name 'DATE_OR_RANGE'
188
219
  cmd.flag [:from], type: DateRangeString
220
+ when :save
221
+ cmd.desc 'Save all current command line options as a new view'
222
+ cmd.arg_name 'VIEW_NAME'
223
+ cmd.flag %i[save]
189
224
  end
190
225
  end
@@ -7,9 +7,13 @@ module Doing
7
7
 
8
8
  attr_accessor :entries, :change_date
9
9
 
10
- def initialize(version, content)
10
+ attr_writer :prefix
11
+
12
+ def initialize(version, content, prefix: false, only: %i[changed new improved fixed])
11
13
  @version = Version.new(version)
12
14
  @content = content
15
+ @prefix = prefix
16
+ @only = only
13
17
  parse_entries
14
18
  end
15
19
 
@@ -18,10 +22,10 @@ module Doing
18
22
  @change_date = Time.parse(date[0]) if date
19
23
 
20
24
  @entries = []
21
- types = @content.scan(/(?<=\n|\A)#### (NEW|IMPROVED|FIXED)(.*?)(?=\n####|\Z)/m)
25
+ types = @content.scan(/(?<=\n|\A)#### (CHANGED|NEW|IMPROVED|FIXED)(.*?)(?=\n####|\Z)/m)
22
26
  types.each do |type|
23
27
  type[1].scan(/\s*- +(.*?)$/).each do |entry|
24
- @entries << Entry.new(entry[0].strip, type[0])
28
+ @entries << Entry.new(entry[0].strip, type[0], prefix: @prefix)
25
29
  end
26
30
  end
27
31
  end
@@ -57,7 +61,7 @@ module Doing
57
61
  end
58
62
 
59
63
  def split_items
60
- items = { new: [], improved: [], fixed: [], other: [] }
64
+ items = { changed: [], new: [], improved: [], fixed: [], other: [] }
61
65
 
62
66
  @entries.each do |e|
63
67
  type = e.type.downcase.to_sym
@@ -76,6 +80,8 @@ module Doing
76
80
  out = ["### __#{@version}__#{date}"]
77
81
 
78
82
  split_items.each do |type, members|
83
+ next unless @only.include?(type)
84
+
79
85
  if members.count.positive?
80
86
  out << "#### #{type.to_s.capitalize}"
81
87
  out << members.map(&:to_s).join("\n")
@@ -88,7 +94,9 @@ module Doing
88
94
  def changes_only
89
95
  out = []
90
96
 
91
- split_items.each do |_, members|
97
+ split_items.each do |type, members|
98
+ next unless @only.include?(type)
99
+
92
100
  out << members.map(&:to_s).join("\n")
93
101
  end
94
102
 
@@ -6,8 +6,10 @@ module Doing
6
6
  attr_reader :changes
7
7
  attr_writer :changes_only
8
8
 
9
- def initialize(lookup: nil, search: nil, changes: false, sort: :desc)
9
+ def initialize(lookup: nil, search: nil, changes: false, sort: :desc, prefix: false, only: %i[changed new improved fixed])
10
10
  @changes_only = changes
11
+ @prefix = prefix
12
+ @only = only
11
13
  changelog = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'CHANGELOG.md'))
12
14
  raise 'Error locating changelog' unless File.exist?(changelog)
13
15
 
@@ -56,9 +58,10 @@ module Doing
56
58
  @changes = @content.scan(change_rx).each_with_object([]) do |m, a|
57
59
  next if m[0].nil? || m[1].nil?
58
60
 
59
- a << Change.new(m[0], m[1].strip)
61
+ a << Change.new(m[0], m[1].strip, prefix: @prefix)
60
62
  end
61
63
 
64
+ select_type
62
65
  lookup(lookup) unless lookup.nil?
63
66
  search(search) unless search.nil?
64
67
  end
@@ -98,5 +101,11 @@ module Doing
98
101
 
99
102
  @changes.delete_if { |c| c.nil? || c.entries.nil? }
100
103
  end
104
+
105
+ def select_type
106
+ @changes.map do |c|
107
+ c.entries.delete_if { |e| !@only.include?(e.type.normalize_change_type) }
108
+ end
109
+ end
101
110
  end
102
111
  end
@@ -5,17 +5,24 @@ module Doing
5
5
  class Entry
6
6
  attr_reader :type, :string
7
7
 
8
- def initialize(string, type)
8
+ attr_writer :prefix
9
+
10
+ def initialize(string, type, prefix: false)
9
11
  @string = string
10
12
  @type = type
13
+ @prefix = prefix
11
14
  end
12
15
 
13
16
  def clean(string)
14
17
  string.gsub(/\|/, '\|')
15
18
  end
16
19
 
20
+ def print_prefix
21
+ @prefix ? "#{@type}: " : ''
22
+ end
23
+
17
24
  def to_s
18
- "- #{clean(@string)}"
25
+ "- #{print_prefix}#{clean(@string)}"
19
26
  end
20
27
  end
21
28
  end
@@ -361,6 +361,23 @@ module Doing
361
361
  config
362
362
  end
363
363
 
364
+ ##
365
+ ## Save a set of options to the `views` configuration
366
+ ##
367
+ ## @param view [Hash] view options
368
+ ## @param title [String] view title
369
+ ##
370
+ def save_view(view, title)
371
+ title.downcase!
372
+ user_config = Util.safe_load_file(config_file)
373
+ user_config['views'] = {} unless user_config.key?('views')
374
+ user_config['views'][title] = view
375
+ Util.write_to_file(config_file, YAML.dump(user_config), backup: true)
376
+ Doing.logger.warn('Config:', %(View "#{title}" saved to #{config_file}))
377
+ Doing.logger.info('Config:', %(to use, run `doing view #{title}`))
378
+ Hooks.trigger :post_config, self
379
+ end
380
+
364
381
  # @private
365
382
  def inspect
366
383
  %(<Doing::Configuration #{@settings.hash}>)
data/lib/doing/hash.rb CHANGED
@@ -40,14 +40,46 @@ module Doing
40
40
 
41
41
  # Turn all keys into string
42
42
  #
43
- # Return a copy of the hash where all its keys are strings
43
+ # If the hash has both a string and a symbol for key,
44
+ # keep the string value, discarding the symnbol value
45
+ #
46
+ # @return [Hash] a copy of the hash where all its
47
+ # keys are strings
48
+ #
44
49
  def stringify_keys
45
- each_with_object({}) { |(k, v), hsh| hsh[k.to_s] = v.is_a?(Hash) ? v.stringify_keys : v }
50
+ each_with_object({}) do |(k, v), hsh|
51
+ next if k.is_a?(Symbol) && key?(k.to_s)
52
+
53
+ hsh[k.to_s] = v.is_a?(Hash) ? v.stringify_keys : v
54
+ end
46
55
  end
47
56
 
48
57
  # Turn all keys into symbols
58
+ #
59
+ # If the hash has both a string and a symbol for a key,
60
+ # keep the symbol value and discard the string value
61
+ #
62
+ # @return [Hash] a copy of the hash where all its
63
+ # keys are symbols
64
+ #
49
65
  def symbolize_keys
50
- each_with_object({}) { |(k, v), hsh| hsh[k.to_sym] = v.is_a?(Hash) ? v.symbolize_keys : v }
66
+ each_with_object({}) do |(k, v), hsh|
67
+ next if k.is_a?(String) && key?(k.to_sym)
68
+
69
+ hsh[k.to_sym] = v.is_a?(Hash) ? v.symbolize_keys : v
70
+ end
71
+ end
72
+
73
+ def stringify_values
74
+ transform_values do |v|
75
+ if v.is_a?(Hash)
76
+ v.stringify_values
77
+ elsif v.is_a?(Symbol)
78
+ v.to_s
79
+ else
80
+ v
81
+ end
82
+ end
51
83
  end
52
84
 
53
85
  # Set a nested hash value using an array
@@ -61,30 +93,102 @@ module Doing
61
93
  #
62
94
  def deep_set(path, value)
63
95
  if path.count == 1
64
- unless value.nil? || value =~ /^ *$/
65
- self[path[0]] = value
66
- else
96
+ if value.nil? || value =~ /^ *$/
67
97
  delete(path[0])
98
+ else
99
+ self[path[0]] = value
68
100
  end
101
+ elsif value
102
+ self.default_proc = ->(h, k) { h[k] = Hash.new(&h.default_proc) }
103
+ dig(*path[0..-2])[path.fetch(-1)] = value
69
104
  else
70
- if value
71
- self.default_proc = ->(h, k) { h[k] = Hash.new(&h.default_proc) }
72
- dig(*path[0..-2])[path.fetch(-1)] = value
73
- else
74
- return self unless dig(*path)
75
-
76
- dig(*path[0..-2]).delete(path.fetch(-1))
77
- path.pop
78
- cleaned = self
79
- path.each do |key|
80
- if cleaned[key].empty?
81
- cleaned.delete(key)
82
- break
83
- end
84
- cleaned = cleaned[key]
105
+ return self unless dig(*path)
106
+
107
+ dig(*path[0..-2]).delete(path.fetch(-1))
108
+ path.pop
109
+ cleaned = self
110
+ path.each do |key|
111
+ if cleaned[key].empty?
112
+ cleaned.delete(key)
113
+ break
85
114
  end
86
- empty? ? nil : self
115
+ cleaned = cleaned[key]
87
116
  end
117
+ empty? ? nil : self
118
+ end
119
+ end
120
+
121
+ ##
122
+ ## Rename a key, deleting old key
123
+ ##
124
+ ## @param old_key The original key
125
+ ## @param new_key The new key
126
+ ## @param keep [Boolean] if true, keep old key
127
+ ## in addition to new key
128
+ ##
129
+ def rename_key(old_key, new_key, keep: false)
130
+ return unless key?(old_key)
131
+
132
+ self[new_key] = self[old_key]
133
+ self[new_key.to_s] = self[old_key] if key?(new_key.to_s)
134
+ delete(old_key) unless keep
135
+ end
136
+
137
+ ##
138
+ ## Rename keys in batch
139
+ ##
140
+ ## @param pairs [Array] pairs of old and new keys
141
+ ##
142
+ def rename_keys(*pairs)
143
+ pairs.each { |p| rename_key(p[0], p[1]) }
144
+ end
145
+
146
+ ##
147
+ ## Remove keys with empty values
148
+ ##
149
+ def remove_empty
150
+ delete_if { |k, v| !v.is_a?(FalseClass) && !v.good? }
151
+ end
152
+
153
+ def tag_filter_to_options
154
+ hsh = dup
155
+ if hsh.key?(:tag_filter)
156
+ hsh[:tags] = hsh[:tag_filter][:tags]
157
+ hsh[:bool] = hsh[:tag_filter][:bool]
158
+ hsh.delete(:tag_filter)
159
+ end
160
+ replace hsh
161
+ end
162
+
163
+ ##
164
+ ## Convert an options hash to a view config
165
+ ##
166
+ ## @return [Hash] View representation of the object.
167
+ ##
168
+ def to_view
169
+ hsh = symbolize_keys
170
+ %w[x save c a s o h e editor m menu i interactive d delete t fuzzy time_filter sort_tags].each do |key|
171
+ hsh.delete(key.to_sym) if hsh.key?(key.to_sym)
172
+ end
173
+
174
+ hsh.delete_unless_key(:tag, %i[bool])
175
+ hsh.delete_unless_key(:search, %i[exact case])
176
+ hsh.rename_keys(%i[not negate], %i[tag tags])
177
+ hsh.tag_filter_to_options
178
+
179
+ hsh = hsh.remove_empty.stringify_keys.stringify_values
180
+ hsh.keys.sort.each_with_object({}) { |k, out| out[k] = hsh[k] }
181
+ end
182
+
183
+ ##
184
+ ## Delete array of keys unless key exists
185
+ ##
186
+ ## @param key The key to verify
187
+ ## @param to_delete [Array] the keys to delete if key doesn't exist
188
+ ##
189
+ def delete_unless_key(key, to_delete)
190
+ unless key?(key)
191
+ to_delete.each { |k| delete(k) }
88
192
  end
89
193
  end
90
194
  end
@@ -155,6 +155,19 @@ module Doing
155
155
  def normalize_trigger!
156
156
  replace normalize_trigger
157
157
  end
158
+
159
+ def normalize_change_type
160
+ case self
161
+ when /^c/i
162
+ :changed
163
+ when /^i/i
164
+ :improved
165
+ when /^f/i
166
+ :fixed
167
+ when /^n/i
168
+ :new
169
+ end
170
+ end
158
171
  end
159
172
 
160
173
  ##
data/lib/doing/pager.rb CHANGED
@@ -73,7 +73,7 @@ module Doing
73
73
  [
74
74
  Doing.setting('editors.pager'),
75
75
  ENV['PAGER'],
76
- 'less -Xr',
76
+ 'less -FXr',
77
77
  ENV['GIT_PAGER'],
78
78
  git_pager,
79
79
  'more -r'
data/lib/doing/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Doing
2
- VERSION = '2.1.42'
2
+ VERSION = '2.1.43'
3
3
  end
@@ -100,10 +100,28 @@ module Doing
100
100
  ##
101
101
  ## @param title [String] The title of the view to retrieve
102
102
  ##
103
- def get_view(title)
104
- return Doing.setting(['views', title], nil)
103
+ def get_view(title, fallback: nil)
104
+ Doing.setting(['views', title], fallback)
105
+ end
106
+
107
+ def rename_view_keys(view)
108
+ options = view.symbolize_keys
109
+ # options.rename_key(:tags, :tag, keep: true)
110
+ options.rename_key(:output_format, :output)
111
+ options.rename_key(:tags_bool, :bool)
112
+ options.rename_key(:tag_sort, :sort_tags)
113
+ options.rename_key(:negate, :not)
114
+ options.rename_key(:order, :sort)
115
+
116
+ options
117
+ end
105
118
 
106
- false
119
+ def view_to_options(title)
120
+ view = rename_view_keys(get_view(guess_view(title)))
121
+ view.deep_merge(rename_view_keys(get_view(guess_view(view[:parent]), fallback: {}))) if view.key?(:parent)
122
+ view.deep_merge(rename_view_keys(get_view(view[:config_template], fallback: {}))) if view.key?(:config_template)
123
+ view.deep_merge(Doing.setting('templates.default').symbolize_keys)
124
+ view
107
125
  end
108
126
 
109
127
  private
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: doing
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.42
4
+ version: 2.1.43
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-18 00:00:00.000000000 Z
11
+ date: 2022-03-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: github-markup
@@ -489,6 +489,7 @@ files:
489
489
  - docs/doc/BooleanTermParser/QueryParser.html
490
490
  - docs/doc/BooleanTermParser/QueryTransformer.html
491
491
  - docs/doc/Doing.html
492
+ - docs/doc/Doing/ArrayCleanup.html
492
493
  - docs/doc/Doing/ArrayNestedHash.html
493
494
  - docs/doc/Doing/ArrayTags.html
494
495
  - docs/doc/Doing/CLIFormat.html