doing 2.1.55 → 2.1.58

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 (131) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +1 -1
  5. data/bin/commands/completion.rb +1 -1
  6. data/bin/commands/recent.rb +15 -18
  7. data/bin/commands/show.rb +13 -4
  8. data/bin/commands/tag_dir.rb +1 -1
  9. data/docs/doc/Array.html +1 -1
  10. data/docs/doc/BooleanTermParser/Clause.html +1 -1
  11. data/docs/doc/BooleanTermParser/Operator.html +1 -1
  12. data/docs/doc/BooleanTermParser/Query.html +1 -1
  13. data/docs/doc/BooleanTermParser/QueryParser.html +1 -1
  14. data/docs/doc/BooleanTermParser/QueryTransformer.html +1 -1
  15. data/docs/doc/BooleanTermParser.html +1 -1
  16. data/docs/doc/Doing/ArrayCleanup.html +1 -1
  17. data/docs/doc/Doing/ArrayNestedHash.html +1 -1
  18. data/docs/doc/Doing/ArrayTags.html +1 -1
  19. data/docs/doc/Doing/CSVExport.html +1 -1
  20. data/docs/doc/Doing/CalendarImport.html +1 -1
  21. data/docs/doc/Doing/Change.html +1 -1
  22. data/docs/doc/Doing/Changes.html +1 -1
  23. data/docs/doc/Doing/ChronifyArray.html +1 -1
  24. data/docs/doc/Doing/ChronifyNumeric.html +1 -1
  25. data/docs/doc/Doing/ChronifyString.html +1 -1
  26. data/docs/doc/Doing/Color.html +35 -1
  27. data/docs/doc/Doing/Completion/BashCompletions.html +1 -1
  28. data/docs/doc/Doing/Completion/FigCompletions.html +1 -1
  29. data/docs/doc/Doing/Completion/FishCompletions.html +1 -1
  30. data/docs/doc/Doing/Completion/StringUtils.html +1 -1
  31. data/docs/doc/Doing/Completion/ZshCompletions.html +1 -1
  32. data/docs/doc/Doing/Completion.html +1 -1
  33. data/docs/doc/Doing/Configuration.html +1 -1
  34. data/docs/doc/Doing/DayOneRenderer.html +1 -1
  35. data/docs/doc/Doing/DayoneExport.html +1 -1
  36. data/docs/doc/Doing/DoingExport.html +1 -1
  37. data/docs/doc/Doing/DoingImport.html +1 -1
  38. data/docs/doc/Doing/Entry.html +1 -1
  39. data/docs/doc/Doing/Errors/DoingNoTraceError.html +1 -1
  40. data/docs/doc/Doing/Errors/DoingRuntimeError.html +1 -1
  41. data/docs/doc/Doing/Errors/DoingStandardError.html +1 -1
  42. data/docs/doc/Doing/Errors/EmptyInput.html +1 -1
  43. data/docs/doc/Doing/Errors/HistoryLimitError.html +1 -1
  44. data/docs/doc/Doing/Errors/InvalidPlugin.html +1 -1
  45. data/docs/doc/Doing/Errors/MissingBackupFile.html +1 -1
  46. data/docs/doc/Doing/Errors/NoResults.html +1 -1
  47. data/docs/doc/Doing/Errors/PluginException.html +1 -1
  48. data/docs/doc/Doing/Errors/UserCancelled.html +1 -1
  49. data/docs/doc/Doing/Errors/WrongCommand.html +1 -1
  50. data/docs/doc/Doing/Errors.html +1 -1
  51. data/docs/doc/Doing/HTMLExport.html +1 -1
  52. data/docs/doc/Doing/Hooks.html +1 -1
  53. data/docs/doc/Doing/Item.html +3 -3
  54. data/docs/doc/Doing/ItemDates.html +1 -1
  55. data/docs/doc/Doing/ItemQuery.html +82 -1
  56. data/docs/doc/Doing/ItemState.html +1 -1
  57. data/docs/doc/Doing/ItemTags.html +1 -1
  58. data/docs/doc/Doing/Items.html +1 -1
  59. data/docs/doc/Doing/JSONExport.html +1 -1
  60. data/docs/doc/Doing/JSONImport.html +1 -1
  61. data/docs/doc/Doing/Logger.html +1 -1
  62. data/docs/doc/Doing/MarkdownExport.html +1 -1
  63. data/docs/doc/Doing/Note.html +1 -1
  64. data/docs/doc/Doing/Pager.html +1 -1
  65. data/docs/doc/Doing/Plugins.html +1 -1
  66. data/docs/doc/Doing/Prompt.html +2 -2
  67. data/docs/doc/Doing/PromptChoose.html +1 -1
  68. data/docs/doc/Doing/PromptFZF.html +1 -1
  69. data/docs/doc/Doing/PromptInput.html +1 -1
  70. data/docs/doc/Doing/PromptSTD.html +1 -1
  71. data/docs/doc/Doing/PromptYN.html +1 -1
  72. data/docs/doc/Doing/Section.html +1 -1
  73. data/docs/doc/Doing/StringHighlight.html +1 -1
  74. data/docs/doc/Doing/StringNormalize.html +1 -1
  75. data/docs/doc/Doing/StringQuery.html +1 -1
  76. data/docs/doc/Doing/StringTags.html +1 -1
  77. data/docs/doc/Doing/StringTransform.html +1 -1
  78. data/docs/doc/Doing/StringTruncate.html +1 -1
  79. data/docs/doc/Doing/StringURL.html +1 -1
  80. data/docs/doc/Doing/SymbolNormalize.html +1 -1
  81. data/docs/doc/Doing/TaskPaperExport.html +1 -1
  82. data/docs/doc/Doing/TemplateExport.html +2 -2
  83. data/docs/doc/Doing/TemplateString.html +2 -2
  84. data/docs/doc/Doing/TimingImport.html +1 -1
  85. data/docs/doc/Doing/Types.html +1 -1
  86. data/docs/doc/Doing/Util/Backup.html +1 -1
  87. data/docs/doc/Doing/Util.html +1 -1
  88. data/docs/doc/Doing/Version.html +1 -1
  89. data/docs/doc/Doing/WWID.html +36 -2
  90. data/docs/doc/Doing.html +2 -2
  91. data/docs/doc/FalseClass.html +1 -1
  92. data/docs/doc/GLI/Commands/Help.html +1 -1
  93. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
  94. data/docs/doc/GLI/Commands.html +1 -1
  95. data/docs/doc/GLI.html +1 -1
  96. data/docs/doc/Hash.html +34 -5
  97. data/docs/doc/Numeric.html +1 -1
  98. data/docs/doc/Object.html +1 -1
  99. data/docs/doc/PhraseParser/Operator.html +1 -1
  100. data/docs/doc/PhraseParser/PhraseClause.html +1 -1
  101. data/docs/doc/PhraseParser/Query.html +1 -1
  102. data/docs/doc/PhraseParser/QueryParser.html +1 -1
  103. data/docs/doc/PhraseParser/QueryTransformer.html +1 -1
  104. data/docs/doc/PhraseParser/TermClause.html +1 -1
  105. data/docs/doc/PhraseParser.html +1 -1
  106. data/docs/doc/Status.html +1 -1
  107. data/docs/doc/String.html +2 -2
  108. data/docs/doc/Symbol.html +1 -1
  109. data/docs/doc/Time.html +1 -1
  110. data/docs/doc/TrueClass.html +1 -1
  111. data/docs/doc/_index.html +1 -1
  112. data/docs/doc/file.README.html +2 -2
  113. data/docs/doc/index.html +2 -2
  114. data/docs/doc/method_list.html +443 -419
  115. data/docs/doc/top-level-namespace.html +1 -1
  116. data/doing.rdoc +15 -8
  117. data/lib/completion/_doing.zsh +1 -1
  118. data/lib/completion/doing.bash +2 -2
  119. data/lib/completion/doing.fish +3 -2
  120. data/lib/completion/doing.ts +14 -4
  121. data/lib/doing/colors.rb +14 -1
  122. data/lib/doing/hash.rb +6 -0
  123. data/lib/doing/item/query.rb +137 -16
  124. data/lib/doing/logger.rb +3 -4
  125. data/lib/doing/plugins/export/markdown_export.rb +4 -1
  126. data/lib/doing/template_string.rb +3 -2
  127. data/lib/doing/version.rb +1 -1
  128. data/lib/doing/wwid/display.rb +1 -2
  129. data/lib/doing/wwid/filter.rb +14 -133
  130. data/lib/doing/wwid/modify.rb +1 -0
  131. metadata +2 -2
@@ -216,7 +216,7 @@
216
216
  </div>
217
217
 
218
218
  <div id="footer">
219
- Generated on Thu May 26 07:14:02 2022 by
219
+ Generated on Wed Jun 1 10:40:46 2022 by
220
220
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
221
221
  0.9.27 (ruby-3.0.1).
222
222
  </div>
data/doing.rdoc CHANGED
@@ -5,7 +5,7 @@ record of what you've been doing, complete with tag-based time tracking. The
5
5
  command line tool allows you to add entries, annotate with tags and notes, and
6
6
  view your entries with myriad options, with a focus on a "natural" language syntax.
7
7
 
8
- v2.1.55
8
+ v2.1.58
9
9
 
10
10
  === Global Options
11
11
  === --config_file arg
@@ -531,14 +531,14 @@ Deprecated, specify shell as argument to subcommand
531
531
  ====== Command: <tt>generate [zsh|bash|fish|all]</tt>
532
532
  Generate completion scripts, including custom plugins and command options
533
533
 
534
- Argument specifies which shell to install for: zsh, bash, fish, all
534
+ Argument specifies which shell to generate for: zsh, bash, fish, all
535
535
  ======= Options
536
536
  ======= -f|--file PATH
537
537
 
538
538
  Alternative file to write output to
539
539
 
540
540
  [Default Value] None
541
- Argument specifies which shell to install for: zsh, bash, fish, all
541
+ Argument specifies which shell to generate for: zsh, bash, fish, all
542
542
 
543
543
  ======= --stdout
544
544
  Output result to STDOUT only
@@ -2333,12 +2333,11 @@ Output to export format (csv|dayone|dayone-days|dayone-entries|doing|html|json|m
2333
2333
  [Default Value] None
2334
2334
 
2335
2335
 
2336
- ===== -s|--sort ORDER
2336
+ ===== -s|--section NAME
2337
2337
 
2338
- Sort order (asc/desc)
2338
+ Only show entries within section
2339
2339
 
2340
- [Default Value] asc
2341
- [Must Match] (?i-mx:^(?:a(?:sc)?|d(?:esc)?)$)
2340
+ [Default Value] None
2342
2341
 
2343
2342
 
2344
2343
  ===== --save VIEW_NAME
@@ -2356,6 +2355,14 @@ Filter entries using a search query, surround with slashes for regex (e.g. "/que
2356
2355
  [Default Value] None
2357
2356
 
2358
2357
 
2358
+ ===== --sort ORDER
2359
+
2360
+ Sort order (asc/desc)
2361
+
2362
+ [Default Value] asc
2363
+ [Must Match] (?i-mx:^(?:a(?:sc)?|d(?:esc)?)$)
2364
+
2365
+
2359
2366
  ===== --tag TAG
2360
2367
 
2361
2368
  Filter entries by tag. Combine multiple tags with a comma. Wildcards allowed (*, ?)
@@ -2721,7 +2728,7 @@ Force exact search string matching (case sensitive)
2721
2728
  Set the default tags for the current directory
2722
2729
 
2723
2730
  Adds default_tags to a .doingrc file in the current directory. Any entry created in this directory or its
2724
- subdirectories will be tagged with the default tags. You can modify these any time using the `config set` commnand or
2731
+ subdirectories will be tagged with the default tags. You can modify these any time using the `config set` command or
2725
2732
  manually editing the .doingrc file.
2726
2733
  ===== Options
2727
2734
  ===== --clear
@@ -174,7 +174,7 @@ function _doing() {
174
174
  args=( {'(--archive)-a','(-a)--archive'}"[Archive selected items]" "--after[Select entries newer than date]:DATE_STRING:" "--resume[Copy selection as a new entry with current time and no @done tag]" "--before[Select entries older than date]:DATE_STRING:" {'(--cancel)-c','(-c)--cancel'}"[Cancel selected items]" "--case[Case sensitivity for search string matching [(c)ase-sensitive]:TYPE:" {'(--delete)-d','(-d)--delete'}"[Delete selected items]" {'(--editor)-e','(-e)--editor'}"[Edit selected item(s)]" {'(--finish)-f','(-f)--finish'}"[Add @done with current time to selected item(s)]" "--flag[Add flag to selected item(s)]" "--force[Perform action without confirmation]" "--from[Date range]:DATE_OR_RANGE:" {'(--move)-m','(-m)--move'}"[Move selected items to section]:SECTION:" "--menu[Use --no-menu to skip the interactive menu]" "--not[Select items that *don't* match search/tag filters]" {'(--output)-o','(-o)--output'}"[Output entries to format]:FORMAT:" {'(--query)-q','(-q)--query'}"[Initial search query for filtering]:QUERY:" {'(--remove)-r','(-r)--remove'}"[Reverse -c]" {'(--section)-s','(-s)--section'}"[Select from a specific section]:SECTION:" "--save_to[Save selected entries to file using --output format]:FILE:" "--search[Filter entries using a search query]:QUERY:" {'(--tag)-t','(-t)--tag'}"[Tag selected entries]:TAG:" "--val[Perform a tag value query]:QUERY:" {'(--exact)-x','(-x)--exact'}"[Force exact search string matching]" )
175
175
  ;;
176
176
  show)
177
- args=( {'(--age)-a','(-a)--age'}"[Age]:AGE:" "--after[Show entries newer than date]:DATE_STRING:" "--before[Show entries older than date]:DATE_STRING:" "--bool[Boolean used to combine multiple tags]:BOOLEAN:" {'(--count)-c','(-c)--count'}"[Max count to show]:MAX:" "--case[Case sensitivity for search string matching [(c)ase-sensitive]:TYPE:" "--config_template[Output using a template from configuration]:TEMPLATE_KEY:" "--duration[Show elapsed time on entries without @done tag]" {'(--editor)-e','(-e)--editor'}"[Edit matching entries with vim]" "--from[Date range]:DATE_OR_RANGE:" {'(--hilite)-h','(-h)--hilite'}"[Highlight search matches in output]" {'(--interactive)-i','(-i)--interactive'}"[Select from a menu of matching entries to perform additional operations]" {'(--menu)-m','(-m)--menu'}"[Select section or tag to display from a menu]" "--not[Show items that *don't* match search/tag filters]" {'(--output)-o','(-o)--output'}"[Output to export format]:FORMAT:" "--only_timed[Only show items with recorded time intervals]" {'(--sort)-s','(-s)--sort'}"[Sort order]:ORDER:" "--save[Save all current command line options as a new view]:VIEW_NAME:" "--search[Filter entries using a search query]:QUERY:" {'(--times)-t','(-t)--times'}"[Show time intervals on @done tasks]" "--tag[Filter entries by tag]:TAG:" "--tag_order[Tag sort direction]:DIRECTION:" "--tag_sort[Sort tags by]:KEY:" "--template[Override output format with a template string containing %placeholders]:TEMPLATE_STRING:" "--title[Title string to be used for output formats that require it]:TITLE:" "--totals[Show time totals at the end of output]" "--val[Perform a tag value query]:QUERY:" {'(--exact)-x','(-x)--exact'}"[Force exact search string matching]" )
177
+ args=( {'(--age)-a','(-a)--age'}"[Age]:AGE:" "--after[Show entries newer than date]:DATE_STRING:" "--before[Show entries older than date]:DATE_STRING:" "--bool[Boolean used to combine multiple tags]:BOOLEAN:" {'(--count)-c','(-c)--count'}"[Max count to show]:MAX:" "--case[Case sensitivity for search string matching [(c)ase-sensitive]:TYPE:" "--config_template[Output using a template from configuration]:TEMPLATE_KEY:" "--duration[Show elapsed time on entries without @done tag]" {'(--editor)-e','(-e)--editor'}"[Edit matching entries with vim]" "--from[Date range]:DATE_OR_RANGE:" {'(--hilite)-h','(-h)--hilite'}"[Highlight search matches in output]" {'(--interactive)-i','(-i)--interactive'}"[Select from a menu of matching entries to perform additional operations]" {'(--menu)-m','(-m)--menu'}"[Select section or tag to display from a menu]" "--not[Show items that *don't* match search/tag filters]" {'(--output)-o','(-o)--output'}"[Output to export format]:FORMAT:" "--only_timed[Only show items with recorded time intervals]" {'(--section)-s','(-s)--section'}"[Only show entries within section]:NAME:" "--save[Save all current command line options as a new view]:VIEW_NAME:" "--search[Filter entries using a search query]:QUERY:" "--sort[Sort order]:ORDER:" {'(--times)-t','(-t)--times'}"[Show time intervals on @done tasks]" "--tag[Filter entries by tag]:TAG:" "--tag_order[Tag sort direction]:DIRECTION:" "--tag_sort[Sort tags by]:KEY:" "--template[Override output format with a template string containing %placeholders]:TEMPLATE_STRING:" "--title[Title string to be used for output formats that require it]:TITLE:" "--totals[Show time totals at the end of output]" "--val[Perform a tag value query]:QUERY:" {'(--exact)-x','(-x)--exact'}"[Force exact search string matching]" )
178
178
  ;;
179
179
  since)
180
180
  args=( "--bool[Boolean used to combine multiple tags]:BOOLEAN:" "--case[Case sensitivity for search string matching [(c)ase-sensitive]:TYPE:" "--config_template[Output using a template from configuration]:TEMPLATE_KEY:" "--duration[Show elapsed time on entries without @done tag]" "--not[Since items that *don't* match search/tag filters]" {'(--output)-o','(-o)--output'}"[Output to export format]:FORMAT:" "--only_timed[Only show items with recorded time intervals]" {'(--section)-s','(-s)--section'}"[Section]:NAME:" "--save[Save all current command line options as a new view]:VIEW_NAME:" "--search[Filter entries using a search query]:QUERY:" {'(--times)-t','(-t)--times'}"[Show time intervals on @done tasks]" "--tag[Filter entries by tag]:TAG:" "--tag_order[Tag sort direction]:DIRECTION:" "--tag_sort[Sort tags by]:KEY:" "--template[Override output format with a template string containing %placeholders]:TEMPLATE_STRING:" "--title[Title string to be used for output formats that require it]:TITLE:" "--totals[Show time totals at the end of output]" "--val[Perform a tag value query]:QUERY:" {'(--exact)-x','(-x)--exact'}"[Force exact search string matching]" )
@@ -276,9 +276,9 @@ local words=$(doing sections)
276
276
  IFS="$OLD_IFS"
277
277
 
278
278
  if [[ "$token" == --* ]]; then
279
- COMPREPLY=( $( compgen -W '--age --after --before --bool --count --case --config_template --duration --editor --from --hilite --interactive --menu --not --output --only_timed --sort --save --search --times --tag --tag_order --tag_sort --template --title --totals --val --exact' -- $token ) )
279
+ COMPREPLY=( $( compgen -W '--age --after --before --bool --count --case --config_template --duration --editor --from --hilite --interactive --menu --not --output --only_timed --section --save --search --sort --times --tag --tag_order --tag_sort --template --title --totals --val --exact' -- $token ) )
280
280
  elif [[ "$token" == -* ]]; then
281
- COMPREPLY=( $( compgen -W '-a -c -e -h -i -m -o -s -t -x --age --after --before --bool --count --case --config_template --duration --editor --from --hilite --interactive --menu --not --output --only_timed --sort --save --search --times --tag --tag_order --tag_sort --template --title --totals --val --exact' -- $token ) )
281
+ COMPREPLY=( $( compgen -W '-a -c -e -h -i -m -o -s -t -x --age --after --before --bool --count --case --config_template --duration --editor --from --hilite --interactive --menu --not --output --only_timed --section --save --search --sort --times --tag --tag_order --tag_sort --template --title --totals --val --exact' -- $token ) )
282
282
  else
283
283
  local nocasematchWasOff=0
284
284
  shopt nocasematch >/dev/null || nocasematchWasOff=1
@@ -470,9 +470,10 @@ complete -c doing -l menu -s m -f -n '__fish_doing_using_command show' -d Selec
470
470
  complete -c doing -l not -f -n '__fish_doing_using_command show' -d Show\ items\ that\ \*don\'t\*\ match\ search/tag\ filters
471
471
  complete -c doing -l output -s o -f -r -n '__fish_doing_using_command show' -d Output\ to\ export\ format
472
472
  complete -c doing -l only_timed -f -n '__fish_doing_using_command show' -d Only\ show\ items\ with\ recorded\ time\ intervals
473
- complete -c doing -l sort -s s -f -r -n '__fish_doing_using_command show' -d Sort\ order
473
+ complete -c doing -l section -s s -f -r -n '__fish_doing_using_command show' -d Only\ show\ entries\ within\ section
474
474
  complete -c doing -l save -f -r -n '__fish_doing_using_command show' -d Save\ all\ current\ command\ line\ options\ as\ a\ new\ view
475
475
  complete -c doing -l search -f -r -n '__fish_doing_using_command show' -d Filter\ entries\ using\ a\ search\ query
476
+ complete -c doing -l sort -f -r -n '__fish_doing_using_command show' -d Sort\ order
476
477
  complete -c doing -l times -s t -f -n '__fish_doing_using_command show' -d Show\ time\ intervals\ on\ @done\ tasks
477
478
  complete -c doing -l tag -f -r -n '__fish_doing_using_command show' -d Filter\ entries\ by\ tag
478
479
  complete -c doing -l tag_order -f -r -n '__fish_doing_using_command show' -d Tag\ sort\ direction
@@ -617,4 +618,4 @@ complete -f -c doing -l sort -x -n '__fish_doing_using_command changes changelog
617
618
  complete -f -c doing -l tag_sort -x -n '__fish_doing_using_command grep search on recent show since today view yesterday' -a 'name time'
618
619
  complete -f -c doing -l tag_order -x -n '__fish_doing_using_command grep search on recent show since today view yesterday' -a 'asc desc'
619
620
  complete -f -c doing -s a -l age -x -n '__fish_doing_using_command show view' -a 'oldest newest'
620
- complete -f -c doing -s s -l section -x -n '__fish_doing_using_command again resume autotag cancel done did finish grep search import last mark flag meanwhile note now next on recent reset begin rotate select since tag tags today view wiki yesterday' -a '(__fish_doing_complete_sections)'
621
+ complete -f -c doing -s s -l section -x -n '__fish_doing_using_command again resume autotag cancel done did finish grep search import last mark flag meanwhile note now next on recent reset begin rotate select show since tag tags today view wiki yesterday' -a '(__fish_doing_complete_sections)'
@@ -3648,11 +3648,11 @@ const completionSpec: Fig.Spec = {
3648
3648
  },
3649
3649
 
3650
3650
  {
3651
- name: ["-s", "--sort"],
3652
- description: "Sort order",
3651
+ name: ["-s", "--section"],
3652
+ description: "Only show entries within section",
3653
3653
  args: {
3654
- name: "ORDER",
3655
- description: "ORDER",
3654
+ name: "NAME",
3655
+ description: "NAME",
3656
3656
  },
3657
3657
 
3658
3658
  },
@@ -3677,6 +3677,16 @@ const completionSpec: Fig.Spec = {
3677
3677
 
3678
3678
  },
3679
3679
 
3680
+ {
3681
+ name: ["--sort"],
3682
+ description: "Sort order",
3683
+ args: {
3684
+ name: "ORDER",
3685
+ description: "ORDER",
3686
+ },
3687
+
3688
+ },
3689
+
3680
3690
  {
3681
3691
  name: ["-t", "--times"],
3682
3692
  description: "Show time intervals on @done tasks",
data/lib/doing/colors.rb CHANGED
@@ -109,7 +109,7 @@ module Doing
109
109
  compiled = ''
110
110
  normalize_color.split('').each do |char|
111
111
  compiled += char
112
- valid_color = compiled if Color.attributes.include?(compiled.to_sym)
112
+ valid_color = compiled if Color.attributes.include?(compiled.to_sym) || compiled =~ /^([fb]g?)?#([a-f0-9]{6})$/i
113
113
  end
114
114
 
115
115
  valid_color
@@ -225,6 +225,19 @@ module Doing
225
225
  module_eval(new_method)
226
226
  end
227
227
 
228
+ def rgb(hex)
229
+ is_bg = hex.match(/^bg?#/) ? true : false
230
+ hex_string = hex.sub(/^([fb]g?)?#/, '')
231
+
232
+ parts = hex_string.match(/(?<r>..)(?<g>..)(?<b>..)/)
233
+ t = []
234
+ %w[r g b].each do |e|
235
+ t << parts[e].hex
236
+ end
237
+ color =
238
+ "\e[#{is_bg ? '48' : '38'};2;#{t.join(';')}m"
239
+ end
240
+
228
241
  # Regular expression that is used to scan for ANSI-sequences while
229
242
  # uncoloring strings.
230
243
  COLORED_REGEXP = /\e\[(?:(?:[349]|10)[0-7]|[0-9])?m/.freeze
data/lib/doing/hash.rb CHANGED
@@ -70,6 +70,12 @@ module Doing
70
70
  end
71
71
  end
72
72
 
73
+ ##
74
+ ## Turn all non-numeric values into strings
75
+ ##
76
+ ## @return [Hash] a copy of the hash where all
77
+ ## non-numeric values are strings
78
+ ##
73
79
  def stringify_values
74
80
  transform_values do |v|
75
81
  if v.is_a?(Hash)
@@ -152,6 +152,133 @@ module Doing
152
152
  negate ? !matches : matches
153
153
  end
154
154
 
155
+ ##
156
+ ## Used by filter_items determine whether an item matches a set of criteria
157
+ ##
158
+ ## @param opt [Hash] filter parameters
159
+ ##
160
+ ## @return [Boolean] whether the item matches all filter criteria
161
+ ##
162
+ def keep_item?(opt)
163
+ item = dup
164
+ time_rx = /^(\d{1,2}+(:\d{1,2}+)?( *(am|pm))?|midnight|noon)$/i
165
+
166
+ keep = true
167
+ if opt[:unfinished]
168
+ finished = item.tags?('done', :and)
169
+ finished = opt[:not] ? !finished : finished
170
+ keep = false if finished
171
+ end
172
+
173
+ if keep && opt[:val]&.count&.positive?
174
+ bool = opt[:bool].normalize_bool if opt[:bool]
175
+ bool ||= :and
176
+ bool = :and if bool == :pattern
177
+
178
+ val_match = opt[:val].nil? || opt[:val].empty? ? true : item.tag_values?(opt[:val], bool)
179
+ keep = false unless val_match
180
+ keep = opt[:not] ? !keep : keep
181
+ end
182
+
183
+ if keep && opt[:tag]
184
+ opt[:tag_bool] = opt[:bool].normalize_bool if opt[:bool]
185
+ opt[:tag_bool] ||= :and
186
+ tag_match = opt[:tag].nil? || opt[:tag].empty? ? true : item.tags?(opt[:tag], opt[:tag_bool])
187
+ keep = false unless tag_match
188
+ keep = opt[:not] ? !keep : keep
189
+ end
190
+
191
+ if keep && opt[:search]
192
+ search_match = if opt[:search].nil? || opt[:search].empty?
193
+ true
194
+ else
195
+ item.search(opt[:search], case_type: opt[:case].normalize_case)
196
+ end
197
+
198
+ keep = false unless search_match
199
+ keep = opt[:not] ? !keep : keep
200
+ end
201
+
202
+ if keep && opt[:date_filter]&.length == 2
203
+ start_date = opt[:date_filter][0]
204
+ end_date = opt[:date_filter][1]
205
+
206
+ in_date_range = if end_date
207
+ item.date >= start_date && item.date <= end_date
208
+ else
209
+ item.date.strftime('%F') == start_date.strftime('%F')
210
+ end
211
+ keep = false unless in_date_range
212
+ keep = opt[:not] ? !keep : keep
213
+ end
214
+
215
+ if keep && opt[:time_filter][0] || opt[:time_filter][1]
216
+ opt[:time_filter].map! { |v| v =~ /(12 *am|midnight)/i ? '00:00' : v }
217
+
218
+ start_string = if opt[:time_filter][0].nil?
219
+ "#{item.date.strftime('%Y-%m-%d')} 00:00"
220
+ else
221
+ "#{item.date.strftime('%Y-%m-%d')} #{opt[:time_filter][0]}"
222
+ end
223
+ start_time = start_string.chronify(guess: :begin)
224
+
225
+ end_string = if opt[:time_filter][1].nil?
226
+ "#{item.date.to_datetime.next_day.strftime('%Y-%m-%d')} 00:00"
227
+ else
228
+ "#{item.date.strftime('%Y-%m-%d')} #{opt[:time_filter][1]}"
229
+ end
230
+ end_time = end_string.chronify(guess: :end) || Time.now
231
+
232
+ in_time_range = item.date >= start_time && item.date <= end_time
233
+
234
+ keep = false unless in_time_range
235
+ keep = opt[:not] ? !keep : keep
236
+ end
237
+
238
+ keep = false if keep && opt[:only_timed] && !item.interval
239
+
240
+ if keep && opt[:tag_filter]
241
+ keep = item.tags?(opt[:tag_filter]['tags'], opt[:tag_filter]['bool'])
242
+ keep = opt[:not] ? !keep : keep
243
+ end
244
+
245
+ if keep && opt[:before]
246
+ before = opt[:before]
247
+ cutoff = if before =~ time_rx
248
+ "#{item.date.strftime('%Y-%m-%d')} #{before}".chronify(guess: :begin)
249
+ elsif before.is_a?(String)
250
+ before.chronify(guess: :begin)
251
+ else
252
+ before
253
+ end
254
+ keep = cutoff && item.date <= cutoff
255
+ keep = opt[:not] ? !keep : keep
256
+ end
257
+
258
+ if keep && opt[:after]
259
+ after = opt[:after]
260
+ cutoff = if after =~ time_rx
261
+ "#{item.date.strftime('%Y-%m-%d')} #{after}".chronify(guess: :end)
262
+ elsif after.is_a?(String)
263
+ after.chronify(guess: :end)
264
+ else
265
+ after
266
+ end
267
+ keep = cutoff && item.date >= cutoff
268
+ keep = opt[:not] ? !keep : keep
269
+ end
270
+
271
+ if keep && opt[:today]
272
+ keep = item.date >= Date.today.to_time && item.date < Date.today.next_day.to_time
273
+ keep = opt[:not] ? !keep : keep
274
+ elsif keep && opt[:yesterday]
275
+ keep = item.date >= Date.today.prev_day.to_time && item.date < Date.today.to_time
276
+ keep = opt[:not] ? !keep : keep
277
+ end
278
+
279
+ keep
280
+ end
281
+
155
282
  private
156
283
 
157
284
  def all_searches?(searches, case_type: :smart)
@@ -191,11 +318,9 @@ module Doing
191
318
  return true unless tags.good?
192
319
 
193
320
  tags.each do |tag|
194
- if tag =~ /done/ && !should_finish?
195
- next
196
- else
197
- return false unless @title =~ /@#{tag.wildcard_to_rx}(?= |\(|\Z)/i
198
- end
321
+ next if tag =~ /done/ && !should_finish?
322
+
323
+ return false unless @title =~ /@#{tag.wildcard_to_rx}(?= |\(|\Z)/i
199
324
  end
200
325
  true
201
326
  end
@@ -204,11 +329,9 @@ module Doing
204
329
  return true unless tags.good?
205
330
 
206
331
  tags.each do |tag|
207
- if tag =~ /done/ && !should_finish?
208
- return false
209
- else
210
- return false if @title =~ /@#{tag.wildcard_to_rx}(?= |\(|\Z)/i
211
- end
332
+ return false if tag =~ /done/ && !should_finish?
333
+
334
+ return false if @title =~ /@#{tag.wildcard_to_rx}(?= |\(|\Z)/i
212
335
  end
213
336
  true
214
337
  end
@@ -217,11 +340,9 @@ module Doing
217
340
  return true unless tags.good?
218
341
 
219
342
  tags.each do |tag|
220
- if tag =~ /done/ && !should_finish?
221
- return true
222
- else
223
- return true if @title =~ /@#{tag.wildcard_to_rx}(?= |\(|\Z)/i
224
- end
343
+ return true if tag =~ /done/ && !should_finish?
344
+
345
+ return true if @title =~ /@#{tag.wildcard_to_rx}(?= |\(|\Z)/i
225
346
  end
226
347
  false
227
348
  end
@@ -393,7 +514,7 @@ module Doing
393
514
  return false if val.nil? || tag_val.nil?
394
515
 
395
516
  # Fail unless both values are of the same class (float or date)
396
- return false unless val.class == tag_val.class
517
+ return false unless val.instance_of?(tag_val.class)
397
518
 
398
519
  is_match = value_number_matches?(tag_val, comp, val)
399
520
 
data/lib/doing/logger.rb CHANGED
@@ -258,7 +258,7 @@ module Doing
258
258
  results = @results.select { |msg| write_message?(msg[:level]) }.uniq
259
259
 
260
260
  if @logdev == $stdout
261
- $stdout.print results.map {|res| res[:message].uncolor }.join("\n")
261
+ $stdout.print results.map { |res| res[:message].uncolor }.join("\n")
262
262
  $stdout.puts
263
263
  else
264
264
  results.each do |msg|
@@ -324,7 +324,6 @@ module Doing
324
324
  end
325
325
  end
326
326
 
327
-
328
327
  def log_change(tags_added: [], tags_removed: [], count: 1, item: nil, single: false)
329
328
  if tags_added.empty? && tags_removed.empty?
330
329
  count(:skipped, level: :debug, message: '%count %items with no change', count: count)
@@ -348,9 +347,9 @@ module Doing
348
347
  if tags_removed.empty?
349
348
  count(:skipped, level: :debug, message: 'no tags removed from %count %items')
350
349
  elsif single && item
351
- added = tags_added.log_tags
350
+ removed = tags_removed.log_tags
352
351
  info('Untagged:',
353
- %(removed #{tags_removed.count == 1 ? 'tag' : 'tags'} #{added} from #{item.title}))
352
+ %(removed #{tags_removed.count == 1 ? 'tag' : 'tags'} #{removed} from #{item.title}))
354
353
  else
355
354
  count(:removed_tags, level: :info, tag: tags_removed, message: '%tags removed from %count %items')
356
355
  end
@@ -55,12 +55,15 @@ module Doing
55
55
  interval = wwid.get_interval(i, record: true) if i.title =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
56
56
  interval ||= false
57
57
 
58
- done = i.title =~ /(?<= |^)@done/ ? 'x' : ' '
58
+ finished = i.title =~ /(?<= |^)@done/ ? true : false
59
+ done = finished ? 'x' : ' '
59
60
 
60
61
  all_items << {
61
62
  date: i.date.strftime('%a %-I:%M%p'),
62
63
  shortdate: i.date.relative_date,
64
+ flagged: i.title =~ /(?<= |^)@#{Doing.setting('marker_tag')}/,
63
65
  done: done,
66
+ finished: finished,
64
67
  note: note,
65
68
  section: i.section,
66
69
  time: interval,
@@ -65,12 +65,13 @@ module Doing
65
65
  working = dup
66
66
  color_array = []
67
67
 
68
- scan(/(?<!\\)(%([a-z]+))/).each do |color|
68
+ scan(/(?<!\\)(%((?:[fb]g?)?#[a-fA-F0-9]{6}|[a-z]+))/).each do |color|
69
69
  valid_color = color[1].validate_color
70
70
  next unless valid_color
71
71
 
72
72
  idx = working.match(/(?<!\\)%#{valid_color}/).begin(0)
73
- color_array.push({ name: valid_color, color: Color.send(valid_color), index: idx })
73
+ color = Color.attributes.include?(valid_color.to_sym) ? Color.send(valid_color) : Color.rgb(valid_color)
74
+ color_array.push({ name: valid_color, color: color, index: idx })
74
75
  working.sub!(/(?<!\\)%#{valid_color}/, '')
75
76
  end
76
77
 
data/lib/doing/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Doing
2
- VERSION = '2.1.55'
2
+ VERSION = '2.1.58'
3
3
  end
@@ -212,7 +212,7 @@ module Doing
212
212
  ##
213
213
  def recent(count = 10, section = nil, opt)
214
214
  opt ||= {}
215
- times = opt[:t] || true
215
+ opt[:times] ||= false
216
216
  opt[:totals] ||= false
217
217
  opt[:sort_tags] ||= false
218
218
 
@@ -236,7 +236,6 @@ module Doing
236
236
  opt[:format] = cfg['date_format']
237
237
  opt[:template] = opt[:template] || cfg['template']
238
238
  opt[:order] = :asc
239
- opt[:times] = times
240
239
 
241
240
  list_section(opt)
242
241
  end
@@ -13,15 +13,19 @@ module Doing
13
13
  # @return [Items] Filtered Items array
14
14
  #
15
15
  def fuzzy_filter_items(items, query, case_type: :smart)
16
- scannable = items.map.with_index { |item, idx| "#{item.title} #{item.note.join(' ')}".gsub(/[|*?!]/, '') + "|#{idx}" }.join("\n")
16
+ scannable = items.map.with_index { |item, idx| "#{item.title} #{item.note.join(' ')}".gsub(/[|*?!]/, '') + "|#{idx}" }.join("\n")
17
17
 
18
- fzf_args = [
19
- '--multi',
20
- %(--filter="#{query.sub(/^'?/, "'")}"),
21
- '--no-sort',
22
- '-d "\|"',
23
- '--nth=1'
24
- ]
18
+ res = `echo #{Shellwords.escape(scannable)}|#{Prompt.fzf} #{fuzzy_filter_args(query, case_type).join(' ')}`
19
+ selected = Items.new
20
+ res.split(/\n/).each do |item|
21
+ idx = item.match(/\|(\d+)$/)[1].to_i
22
+ selected.push(items[idx])
23
+ end
24
+ selected
25
+ end
26
+
27
+ def fuzzy_filter_args(query, case_type)
28
+ fzf_args = ['--multi', %(--filter="#{query.sub(/^'?/, "'")}"), '--no-sort', '-d "\|"', '--nth=1']
25
29
  fzf_args << case case_type.normalize_case
26
30
  when :smart
27
31
  query =~ /[A-Z]/ ? '+i' : '-i'
@@ -30,16 +34,7 @@ module Doing
30
34
  when :ignore
31
35
  '-i'
32
36
  end
33
-
34
- # fzf_args << '-e' if opt[:exact]
35
- # puts fzf_args.join(' ')
36
- res = `echo #{Shellwords.escape(scannable)}|#{Prompt.fzf} #{fzf_args.join(' ')}`
37
- selected = Items.new
38
- res.split(/\n/).each do |item|
39
- idx = item.match(/\|(\d+)$/)[1].to_i
40
- selected.push(items[idx])
41
- end
42
- selected
37
+ fzf_args
43
38
  end
44
39
 
45
40
  ##
@@ -95,122 +90,8 @@ module Doing
95
90
 
96
91
  items.sort_by! { |item| [item.date, item.title.downcase] }.reverse
97
92
 
98
- filtered_items = items.select do |item|
99
- keep = true
100
- if opt[:unfinished]
101
- finished = item.tags?('done', :and)
102
- finished = opt[:not] ? !finished : finished
103
- keep = false if finished
104
- end
105
-
106
- if keep && opt[:val]&.count&.positive?
107
- bool = opt[:bool].normalize_bool if opt[:bool]
108
- bool ||= :and
109
- bool = :and if bool == :pattern
110
-
111
- val_match = opt[:val].nil? || opt[:val].empty? ? true : item.tag_values?(opt[:val], bool)
112
- keep = false unless val_match
113
- keep = opt[:not] ? !keep : keep
114
- end
115
-
116
- if keep && opt[:tag]
117
- opt[:tag_bool] = opt[:bool].normalize_bool if opt[:bool]
118
- opt[:tag_bool] ||= :and
119
- tag_match = opt[:tag].nil? || opt[:tag].empty? ? true : item.tags?(opt[:tag], opt[:tag_bool])
120
- keep = false unless tag_match
121
- keep = opt[:not] ? !keep : keep
122
- end
123
-
124
- if keep && opt[:search]
125
- search_match = if opt[:search].nil? || opt[:search].empty?
126
- true
127
- else
128
- item.search(opt[:search], case_type: opt[:case].normalize_case)
129
- end
93
+ filtered_items = items.select { |item| item.keep_item?(opt) }
130
94
 
131
- keep = false unless search_match
132
- keep = opt[:not] ? !keep : keep
133
- end
134
-
135
- if keep && opt[:date_filter]&.length == 2
136
- start_date = opt[:date_filter][0]
137
- end_date = opt[:date_filter][1]
138
-
139
- in_date_range = if end_date
140
- item.date >= start_date && item.date <= end_date
141
- else
142
- item.date.strftime('%F') == start_date.strftime('%F')
143
- end
144
- keep = false unless in_date_range
145
- keep = opt[:not] ? !keep : keep
146
- end
147
-
148
- if keep && opt[:time_filter][0] || opt[:time_filter][1]
149
- opt[:time_filter].map! { |v| v =~ /(12 *am|midnight)/i ? '00:00' : v }
150
-
151
- start_string = if opt[:time_filter][0].nil?
152
- "#{item.date.strftime('%Y-%m-%d')} 00:00"
153
- else
154
- "#{item.date.strftime('%Y-%m-%d')} #{opt[:time_filter][0]}"
155
- end
156
- start_time = start_string.chronify(guess: :begin)
157
-
158
- end_string = if opt[:time_filter][1].nil?
159
- "#{item.date.to_datetime.next_day.strftime('%Y-%m-%d')} 00:00"
160
- else
161
- "#{item.date.strftime('%Y-%m-%d')} #{opt[:time_filter][1]}"
162
- end
163
- end_time = end_string.chronify(guess: :end) || Time.now
164
-
165
- in_time_range = item.date >= start_time && item.date <= end_time
166
-
167
- keep = false unless in_time_range
168
- keep = opt[:not] ? !keep : keep
169
- end
170
-
171
- keep = false if keep && opt[:only_timed] && !item.interval
172
-
173
- if keep && opt[:tag_filter]
174
- keep = item.tags?(opt[:tag_filter]['tags'], opt[:tag_filter]['bool'])
175
- keep = opt[:not] ? !keep : keep
176
- end
177
-
178
- if keep && opt[:before]
179
- before = opt[:before]
180
- cutoff = if before =~ time_rx
181
- "#{item.date.strftime('%Y-%m-%d')} #{before}".chronify(guess: :begin)
182
- elsif before.is_a?(String)
183
- before.chronify(guess: :begin)
184
- else
185
- before
186
- end
187
- keep = cutoff && item.date <= cutoff
188
- keep = opt[:not] ? !keep : keep
189
- end
190
-
191
- if keep && opt[:after]
192
- after = opt[:after]
193
- cutoff = if after =~ time_rx
194
- "#{item.date.strftime('%Y-%m-%d')} #{after}".chronify(guess: :end)
195
- elsif after.is_a?(String)
196
- after.chronify(guess: :end)
197
- else
198
- after
199
- end
200
- keep = cutoff && item.date >= cutoff
201
- keep = opt[:not] ? !keep : keep
202
- end
203
-
204
- if keep && opt[:today]
205
- keep = item.date >= Date.today.to_time && item.date < Date.today.next_day.to_time
206
- keep = opt[:not] ? !keep : keep
207
- elsif keep && opt[:yesterday]
208
- keep = item.date >= Date.today.prev_day.to_time && item.date < Date.today.to_time
209
- keep = opt[:not] ? !keep : keep
210
- end
211
-
212
- keep
213
- end
214
95
  count = opt[:count].to_i&.positive? ? opt[:count].to_i : filtered_items.count
215
96
 
216
97
  output = Items.new
@@ -281,6 +281,7 @@ module Doing
281
281
 
282
282
  if opt[:remove] || opt[:rename] || opt[:value]
283
283
  rename_to = nil
284
+
284
285
  if opt[:value]
285
286
  rename_to = tag
286
287
  elsif opt[:rename]