doing 2.1.42 → 2.1.45

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 (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +53 -0
  3. data/Gemfile.lock +4 -4
  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 +12 -2
  8. data/bin/commands/last.rb +2 -0
  9. data/bin/commands/on.rb +13 -1
  10. data/bin/commands/recent.rb +4 -1
  11. data/bin/commands/show.rb +8 -0
  12. data/bin/commands/since.rb +6 -2
  13. data/bin/commands/template.rb +14 -25
  14. data/bin/commands/today.rb +4 -1
  15. data/bin/commands/view.rb +36 -73
  16. data/bin/commands/views.rb +102 -5
  17. data/bin/commands/yesterday.rb +3 -1
  18. data/bin/doing +31 -4
  19. data/docs/doc/Array.html +12 -2
  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 +23 -18
  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 +11 -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 +4 -4
  115. data/docs/doc/Symbol.html +1 -1
  116. data/docs/doc/Time.html +68 -3
  117. data/docs/doc/TrueClass.html +11 -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 +511 -407
  122. data/docs/doc/top-level-namespace.html +3 -1
  123. data/doing.rdoc +163 -7
  124. data/lib/completion/_doing.zsh +13 -13
  125. data/lib/completion/doing.bash +22 -22
  126. data/lib/completion/doing.fish +24 -1
  127. data/lib/doing/add_options.rb +40 -1
  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 +21 -0
  132. data/lib/doing/good.rb +18 -1
  133. data/lib/doing/hash.rb +126 -22
  134. data/lib/doing/normalize.rb +13 -0
  135. data/lib/doing/pager.rb +1 -1
  136. data/lib/doing/types.rb +9 -8
  137. data/lib/doing/version.rb +1 -1
  138. data/lib/doing/wwid/display.rb +4 -1
  139. data/lib/doing/wwid/filter.rb +6 -3
  140. data/lib/doing/wwid/wwid.rb +21 -3
  141. data/lib/doing.rb +9 -0
  142. metadata +3 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8021e76952eb60e4eb68c5aa013f558e7e9e5db454bad792c1ae7e5cc495e24c
4
- data.tar.gz: 5eda874992b4f9648c421afdc4429963f2614d08aabba8fb338d4d27c353e258
3
+ metadata.gz: e59c924734be0039ff00042d055094036f77cd0389b3c5bd9fa219df8d18138a
4
+ data.tar.gz: 65000a9977a118261abcda154b1f8af44cca2de16fd5244b54e67aca10d5e90c
5
5
  SHA512:
6
- metadata.gz: 37ce93cc4868cbb5565f18b8cd2a77d61099f9692c5b6bcaacdf9329876faa4bc9ff240adc29ea2f8e4cff76adbadc697f583131dfcdb61379dc998a91d40de4
7
- data.tar.gz: 06d59cd04607005a65f166701873107a8d4817986007940489dfda3247d97d567a4072d62eb05687f50e1ba93eb6341f1db8f5a317df948836fa56945270a8fa
6
+ metadata.gz: 6a13c4113ec1ca306bb51da1f3e7585bfebdb7d7c1623bf60d51fe82f202b301623658cd5a4c9ecdf5ae01aca5b1c7bdd305803c9994cf7d3968fb426c6026c6
7
+ data.tar.gz: 60ad5f63ce19e57a2b15c051a02c0c0f9afc349db11aa726337dd33c919e59cfc28401c0b59f97692d6b90e85c0b5a3f9592c2a24733f52c2d53b327203b0df4
data/CHANGELOG.md CHANGED
@@ -1,3 +1,56 @@
1
+ ### 2.1.45
2
+
3
+ 2022-03-22 08:57
4
+
5
+ #### FIXED
6
+
7
+ - Specifying '12am' as a start time filter resulted in a Nil error
8
+
9
+ ### 2.1.44
10
+
11
+ 2022-03-21 07:46
12
+
13
+ #### NEW
14
+
15
+ - `doing views --remove NAME` to delete a view
16
+ - Deleting all view content in editor (`doing views -e`) deletes the view
17
+
18
+ #### IMPROVED
19
+
20
+ - When saving a view, ignore keys that are the same as the default template
21
+ - Commands accepting `--save` also accept `--title TITLE`
22
+
23
+ #### FIXED
24
+
25
+ - When saving a view, store original date string instead of chronified result
26
+ - Error when testing for valid date
27
+
28
+ ### 2.1.43
29
+
30
+ 2022-03-20 12:44
31
+
32
+ #### NEW
33
+
34
+ - 'parent' key in view config allows inheritance
35
+ - Use `--save NAME` with view commands to store command line options as a view in config
36
+ - Views function as commands, so you can run `doing custom` and get `doing view custom` if 'custom' is not a recognized command
37
+ - Breaking change - boolean switches on the command line no longer override views
38
+ - Add an argument to `doing views` to dump the YAML for a single view
39
+ - Use `doing views NAME --editor` to open the YAML for a single view in the default editor, saving the result to main config
40
+ - Use `doing views [-e] -o json NAME` to dump or edit a view as json instead of YAML
41
+
42
+ #### IMPROVED
43
+
44
+ - `doing changes --only [changed,new,improved,fixed]` to only show changes of a type
45
+ - Allow all show options in view config
46
+ - Disable autocorrect for command names so custom views can better override similarly-spelled commands
47
+ - `doing changes --prefix` will output each change with a type prefix
48
+ - Include -F switch in `less` when paging to avoid pager if less than one screen
49
+
50
+ #### FIXED
51
+
52
+ - `doing templates --list` returning error
53
+
1
54
  ### 2.1.42
2
55
 
3
56
  2022-03-17 09:38
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- doing (2.1.42)
4
+ doing (2.1.45)
5
5
  chronic (~> 0.10, >= 0.10.2)
6
6
  deep_merge (~> 1.2, >= 1.2.1)
7
7
  gli (~> 2.20, >= 2.20.1)
@@ -22,11 +22,11 @@ GEM
22
22
  chronic (0.10.2)
23
23
  deep_merge (1.2.2)
24
24
  github-markup (4.0.0)
25
- gli (2.20.1)
25
+ gli (2.21.0)
26
26
  haml (5.0.4)
27
27
  temple (>= 0.8.0)
28
28
  tilt
29
- kramdown (2.3.1)
29
+ kramdown (2.3.2)
30
30
  rexml
31
31
  parallel (1.21.0)
32
32
  parallel_tests (3.7.3)
@@ -40,7 +40,7 @@ GEM
40
40
  rdoc (6.3.3)
41
41
  redcarpet (3.5.1)
42
42
  rexml (3.2.5)
43
- rouge (3.27.0)
43
+ rouge (3.28.0)
44
44
  safe_yaml (1.0.5)
45
45
  strings (0.2.1)
46
46
  strings-ansi (~> 0.2)
data/README.md CHANGED
@@ -8,7 +8,7 @@ _If you're one of the rare people like me who find this useful, feel free to
8
8
 
9
9
  <!--README-->
10
10
 
11
- The current version of `doing` is <!--VER-->2.1.41<!--END VER-->.
11
+ The current version of `doing` is <!--VER-->2.1.44<!--END VER-->.
12
12
 
13
13
  Find all of the documentation in the [doing wiki][wiki].
14
14
 
@@ -40,6 +40,13 @@ module Doing
40
40
  cmd.desc 'Only output changes, no version numbers, headers, or dates'
41
41
  cmd.switch %i[C changes], default_value: false, negatable: false
42
42
 
43
+ cmd.desc 'Include (CHANGE|NEW|IMPROVED|FIXED) prefix on each line'
44
+ cmd.switch %i[p prefix]
45
+
46
+ cmd.desc 'Only show changes of type(s), comma-separated'
47
+ cmd.arg_name 'TYPES'
48
+ cmd.flag %i[only], default_value: 'changed,new,improved,fixed'
49
+
43
50
  cmd.desc 'Output raw Markdown'
44
51
  cmd.switch %i[m md markdown], default_value: false, negatable: false
45
52
 
@@ -72,10 +79,13 @@ command %i[changes changelog] do |c|
72
79
  cmd.add_examples(c)
73
80
 
74
81
  c.action do |_global_options, options, _args|
82
+ only = options[:only].split(/ *, */).map(&:normalize_change_type)
75
83
  cl = Doing::Changes.new(lookup: options[:lookup],
76
84
  search: options[:search],
77
85
  changes: options[:changes],
78
- sort: options[:sort])
86
+ prefix: options[:prefix],
87
+ sort: options[:sort],
88
+ only: only)
79
89
 
80
90
  if options[:interactive]
81
91
  cl.interactive
data/bin/commands/flag.rb CHANGED
@@ -8,7 +8,7 @@ command %i[mark flag] do |c|
8
8
  c.example 'doing flag --tag project1 --count 2', desc: 'Add @flagged to the last 2 entries tagged @project1'
9
9
  c.example 'doing flag --interactive --search "/(develop|cod)ing/"',
10
10
  desc: 'Find entries matching regular expression and create a menu allowing multiple selections,
11
- selected items will be @flagged'
11
+ selected items will be @flagged'
12
12
 
13
13
  c.desc 'Section'
14
14
  c.arg_name 'SECTION_NAME'
data/bin/commands/grep.rb CHANGED
@@ -25,7 +25,7 @@ command %i[grep search] do |c|
25
25
  c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
26
26
  c.arg_name 'TYPE'
27
27
  c.flag [:case], must_match: REGEX_CASE,
28
- default_value: Doing.settings.dig('search', 'case').normalize_case,
28
+ default_value: Doing.setting('search.case', :smart).normalize_case,
29
29
  type: CaseSymbol
30
30
 
31
31
  c.desc "Highlight search matches in output. Only affects command line output"
@@ -44,11 +44,15 @@ command %i[grep search] do |c|
44
44
  add_options(:tag_filter, c)
45
45
  add_options(:date_filter, c)
46
46
  add_options(:time_display, c)
47
+ add_options(:save, c)
47
48
 
48
49
  c.action do |_global_options, options, args|
49
50
  options[:fuzzy] = false
50
51
 
51
- raise InvalidPlugin.new('output', options[:output]) if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
52
+ if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
53
+ raise InvalidPlugin.new('output', options[:output])
54
+
55
+ end
52
56
 
53
57
  template = Doing.setting(['templates', options[:config_template]]).deep_merge(Doing.settings)
54
58
  tags_color = template.key?('tags_color') ? template['tags_color'] : nil
@@ -66,5 +70,11 @@ command %i[grep search] do |c|
66
70
  options[:tags_color] = tags_color
67
71
 
68
72
  Doing::Pager.page @wwid.list_section(options)
73
+ if options[:save]
74
+ options[:before] = Doing.original_options[:date_begin] if Doing.original_options[:date_begin].good?
75
+ options[:after] = Doing.original_options[:date_end] if Doing.original_options[:date_end].good?
76
+ options[:from] = Doing.original_options[:date_range] if Doing.original_options[:date_range].good?
77
+ Doing.config.save_view(options.to_view, options[:save].downcase)
78
+ end
69
79
  end
70
80
  end
data/bin/commands/last.rb CHANGED
@@ -30,6 +30,7 @@ command :last do |c|
30
30
  add_options(:output_template, c, default_template: 'last')
31
31
  add_options(:search, c)
32
32
  add_options(:tag_filter, c)
33
+ add_options(:save, c)
33
34
 
34
35
  c.action do |global_options, options, _args|
35
36
  options[:fuzzy] = false
@@ -70,6 +71,7 @@ command :last do |c|
70
71
  val: options[:val]
71
72
  })
72
73
  Doing::Pager::page last.strip if last
74
+ Doing.config.save_view(options.to_view, options[:save].downcase) if options[:save]
73
75
  end
74
76
  end
75
77
  end
data/bin/commands/on.rb CHANGED
@@ -20,6 +20,7 @@ command :on do |c|
20
20
  add_options(:search, c)
21
21
  add_options(:tag_filter, c)
22
22
  add_options(:time_filter, c)
23
+ add_options(:save, c)
23
24
 
24
25
  c.action do |_global_options, options, args|
25
26
  if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
@@ -43,6 +44,17 @@ command :on do |c|
43
44
  options[:times] = true if options[:totals]
44
45
  options[:sort_tags] = options[:tag_sort]
45
46
 
46
- Doing::Pager.page @wwid.list_date([start, finish], options[:section], options[:times], options[:output], options).chomp
47
+ Doing::Pager.page @wwid.list_date([start, finish],
48
+ options[:section],
49
+ options[:times],
50
+ options[:output],
51
+ options).chomp
52
+
53
+ if options[:save]
54
+ options[:before] = Doing.original_options[:date_end] if Doing.original_options[:date_end].good?
55
+ options[:after] = Doing.original_options[:date_begin] if Doing.original_options[:date_begin].good?
56
+ options[:from] = Doing.original_options[:date_range] if Doing.original_options[:date_range].good?
57
+ Doing.config.save_view(options.to_view, options[:save].downcase)
58
+ end
47
59
  end
48
60
  end
@@ -17,6 +17,7 @@ command :recent do |c|
17
17
 
18
18
  add_options(:output_template, c, default_template: 'recent')
19
19
  add_options(:time_display, c)
20
+ add_options(:save, c)
20
21
 
21
22
  c.action do |global_options, options, args|
22
23
  section = @wwid.guess_section(options[:section]) || options[:section].cap_first
@@ -53,7 +54,9 @@ command :recent do |c|
53
54
  }
54
55
 
55
56
  Doing::Pager::page @wwid.recent(count, section.cap_first, opts)
56
-
57
+ opts[:count] = count
58
+ opts[:title] = options[:title]
59
+ Doing.config.save_view(opts.to_view, options[:save].downcase) if options[:save]
57
60
  end
58
61
  end
59
62
  end
data/bin/commands/show.rb CHANGED
@@ -47,6 +47,7 @@ command :show do |c|
47
47
  add_options(:search, c)
48
48
  add_options(:tag_filter, c)
49
49
  add_options(:date_filter, c)
50
+ add_options(:save, c)
50
51
 
51
52
  c.action do |global_options, options, args|
52
53
  options[:fuzzy] = false
@@ -153,5 +154,12 @@ command :show do |c|
153
154
  opt[:tags_color] = template['tags_color']
154
155
 
155
156
  Doing::Pager.page @wwid.list_section(opt, items: items)
157
+
158
+ if options[:save]
159
+ opt[:before] = Doing.original_options[:date_begin] if Doing.original_options[:date_begin].good?
160
+ opt[:after] = Doing.original_options[:date_end] if Doing.original_options[:date_end].good?
161
+ opt[:from] = Doing.original_options[:date_range] if Doing.original_options[:date_range].good?
162
+ Doing.config.save_view(opt.to_view, options[:save].downcase)
163
+ end
156
164
  end
157
165
  end
@@ -15,7 +15,7 @@ command :since do |c|
15
15
  add_options(:time_display, c)
16
16
  add_options(:tag_filter, c)
17
17
  add_options(:search, c)
18
-
18
+ add_options(:save, c)
19
19
  c.action do |_global_options, options, args|
20
20
  raise DoingRuntimeError, %(Invalid output type "#{options[:output]}") if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
21
21
 
@@ -25,7 +25,7 @@ command :since do |c|
25
25
 
26
26
  date_string.sub!(/(day) (\d)/, '\1 at \2')
27
27
  date_string.sub!(/(\d+)d( ago)?/, '\1 days ago')
28
-
28
+ Doing.original_options[:date_begin] = date_string
29
29
  start = date_string.chronify(guess: :begin)
30
30
  finish = Time.now
31
31
 
@@ -37,5 +37,9 @@ command :since do |c|
37
37
  options[:sort_tags] = options[:tag_sort]
38
38
 
39
39
  Doing::Pager.page @wwid.list_date([start, finish], options[:section], options[:times], options[:output], options).chomp
40
+ if options[:save]
41
+ options[:after] = Doing.original_options[:date_begin] if Doing.original_options[:date_begin].good?
42
+ Doing.config.save_view(options.to_view, options[:save].downcase)
43
+ end
40
44
  end
41
45
  end
@@ -28,34 +28,23 @@ command :template do |c|
28
28
  else
29
29
  $stdout.puts "Available templates: #{Doing::Plugins.plugin_templates.join(', ')}"
30
30
  end
31
- return
32
- end
33
-
34
- if args.empty?
35
- type = Doing::Prompt.choose_from(Doing::Plugins.plugin_templates, sorted: false, prompt: 'Select template type > ')
36
- type.sub!(/ \(.*?\)$/, '').strip!
37
- options[:save] = Doing::Prompt.yn("Save to #{options[:path]}? (No outputs to STDOUT)", default_response: false)
38
31
  else
39
- type = args[0]
40
- end
41
32
 
42
- raise InvalidPluginType, "No type specified, use `doing template [#{Doing::Plugins.plugin_templates.join('|')}]`" unless type
33
+ if args.empty?
34
+ type = Doing::Prompt.choose_from(Doing::Plugins.plugin_templates, sorted: false, prompt: 'Select template type > ')
35
+ type.sub!(/ \(.*?\)$/, '').strip!
36
+ options[:save] = Doing::Prompt.yn("Save to #{options[:path]}? (No outputs to STDOUT)", default_response: false)
37
+ else
38
+ type = args[0]
39
+ end
40
+
41
+ raise InvalidPluginType, "No type specified, use `doing template [#{Doing::Plugins.plugin_templates.join('|')}]`" unless type
43
42
 
44
- if options[:save]
45
- Doing::Plugins.template_for_trigger(type, save_to: options[:path])
46
- else
47
- $stdout.puts Doing::Plugins.template_for_trigger(type, save_to: nil)
43
+ if options[:save]
44
+ Doing::Plugins.template_for_trigger(type, save_to: options[:path])
45
+ else
46
+ $stdout.puts Doing::Plugins.template_for_trigger(type, save_to: nil)
47
+ end
48
48
  end
49
-
50
- # case args[0]
51
- # when /html|haml/i
52
- # $stdout.puts @wwid.haml_template
53
- # when /css/i
54
- # $stdout.puts @wwid.css_template
55
- # when /markdown|md|erb/i
56
- # $stdout.puts @wwid.markdown_template
57
- # else
58
- # exit_now! 'Invalid type specified, must be HAML or CSS'
59
- # end
60
49
  end
61
50
  end
@@ -15,6 +15,7 @@ command :today do |c|
15
15
  add_options(:output_template, c, default_template: 'today')
16
16
  add_options(:time_filter, c)
17
17
  add_options(:time_display, c)
18
+ add_options(:save, c)
18
19
 
19
20
  c.action do |_global_options, options, _args|
20
21
  raise InvalidPlugin.new('output', options[:output]) if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
@@ -22,7 +23,9 @@ command :today do |c|
22
23
  options[:times] = true if options[:totals]
23
24
  options[:sort_tags] = options[:tag_sort]
24
25
  filter_options = %i[after before times duration from section sort_tags totals tag_order template config_template only_timed].each_with_object({}) { |k, hsh| hsh[k] = options[k] }
25
-
26
+ filter_options[:today] = true
26
27
  Doing::Pager.page @wwid.today(options[:times], options[:output], filter_options).chomp
28
+ filter_options[:title] = options[:title]
29
+ Doing.config.save_view(filter_options.to_view, options[:save].downcase) if options[:save]
27
30
  end
28
31
  end
data/bin/commands/view.rb CHANGED
@@ -15,28 +15,24 @@ command :view do |c|
15
15
  c.arg_name 'COUNT'
16
16
  c.flag %i[c count], must_match: /^\d+$/, type: Integer
17
17
 
18
- c.desc "Output to export format (#{Doing::Plugins.plugin_names(type: :export)})"
19
- c.arg_name 'FORMAT'
20
- c.flag %i[o output]
21
-
22
18
  c.desc 'Age (oldest|newest)'
23
19
  c.arg_name 'AGE'
24
- c.flag %i[age], default_value: :newest, type: AgeSymbol
20
+ c.flag %i[age], type: AgeSymbol
25
21
 
26
22
  c.desc 'Show time intervals on @done tasks'
27
23
  c.switch %i[t times], default_value: true, negatable: true
28
24
 
29
25
  c.desc 'Show elapsed time on entries without @done tag'
30
- c.switch [:duration]
26
+ c.switch [:duration], default_value: false, negatable: false
31
27
 
32
28
  c.desc 'Show intervals with totals at the end of output'
33
29
  c.switch [:totals], default_value: false, negatable: false
34
30
 
35
31
  c.desc 'Include colors in output'
36
- c.switch [:color], default_value: true, negatable: true
32
+ c.switch [:color], negatable: true
37
33
 
38
34
  c.desc "Highlight search matches in output. Only affects command line output"
39
- c.switch %i[h hilite], default_value: Doing.settings.dig('search', 'highlight')
35
+ c.switch %i[h hilite], default_value: false, negatable: true
40
36
 
41
37
  c.desc 'Sort tags by (name|time)'
42
38
  c.arg_name 'KEY'
@@ -53,8 +49,9 @@ command :view do |c|
53
49
  c.switch %i[i interactive], negatable: false, default_value: false
54
50
 
55
51
  add_options(:search, c)
56
- add_options(:tag_filter, c)
52
+ add_options(:tag_filter_no_defaults, c)
57
53
  add_options(:date_filter, c)
54
+ add_options(:output_template_no_defaults, c)
58
55
 
59
56
  c.action do |global_options, options, args|
60
57
  options[:fuzzy] = false
@@ -85,83 +82,55 @@ command :view do |c|
85
82
  Doing.setting('current_section')
86
83
  end
87
84
 
88
- view = @wwid.get_view(title)
85
+ view = @wwid.view_to_options(title)
89
86
 
90
87
  if view
91
- page_title = view['title'] || title.cap_first
92
- only_timed = if (view.key?('only_timed') && view['only_timed']) || options[:only_timed]
93
- true
94
- else
95
- false
96
- end
88
+ options = Doing::Util.deep_merge_hashes(view, options)
97
89
 
98
- template = view['template'] || nil
99
- date_format = view['date_format'] || nil
90
+ options[:totals] = view[:totals] unless options[:totals]
91
+ options[:only_timed] = view[:only_timed] unless options[:only_timed]
92
+ options[:times] = view[:times] if options[:times]
93
+ options[:duration] = view[:duration] unless options[:duration]
94
+ options[:hilite] = view[:hilite] unless options[:hilite]
100
95
 
101
- tags_color = view['tags_color'] || nil
96
+ page_title = options[:title] || title.cap_first
102
97
  tag_filter = false
103
- if options[:tag]
98
+ if options[:tag] && options[:tag].good
104
99
  tag_filter = { 'tags' => [], 'bool' => 'OR' }
105
- bool = options[:bool]
100
+ bool = options[:bool].normalize_bool
106
101
  tag_filter['bool'] = bool
107
102
  tag_filter['tags'] = if bool == :pattern
108
103
  options[:tag]
109
104
  else
110
105
  options[:tag].gsub(/[, ]+/, ' ').split(' ').map(&:strip)
111
106
  end
112
- elsif view.key?('tags') && view['tags'].good?
107
+ options[:tags] = nil
108
+ options[:bool] = bool
109
+ elsif options[:tags]
113
110
  tag_filter = { 'tags' => [], 'bool' => 'OR' }
114
- bool = view.key?('tags_bool') && !view['tags_bool'].nil? ? view['tags_bool'].normalize_bool : :pattern
111
+ bool = options[:bool] ? options[:bool].normalize_bool : :pattern
115
112
  tag_filter['bool'] = bool
116
- tag_filter['tags'] = if view['tags'].instance_of?(Array)
117
- bool == :pattern ? view['tags'].join(' ').strip : view['tags'].map(&:strip)
113
+ tag_filter['tags'] = if options[:tags].instance_of?(Array)
114
+ bool == :pattern ? options[:tags].join(' ').strip : options[:tags].map(&:strip)
118
115
  else
119
- bool == :pattern ? view['tags'].strip : view['tags'].gsub(/[, ]+/, ' ').split(' ').map(&:strip)
116
+ bool == :pattern ? options[:tags].strip : options[:tags].gsub(/[, ]+/, ' ').split(' ').map(&:strip)
120
117
  end
118
+ options[:tags] = nil
119
+ options[:bool] = bool
121
120
  end
122
121
 
123
- # If the -o/--output flag was specified, override any default in the view template
124
- options[:output] ||= view.key?('output_format') ? view['output_format'] : 'template'
125
-
126
- count = if options[:count]
127
- options[:count]
128
- elsif view.key?('count')
129
- view['count']
130
- else
131
- 10
132
- end
133
-
134
- section = if options[:section]
135
- section
136
- else
137
- view['section'] || Doing.setting('current_section')
138
- end
139
- order = if view.key?('order')
140
- view['order'].normalize_order
141
- else
142
- :asc
143
- end
144
-
145
- totals = if options[:totals]
146
- true
147
- else
148
- view['totals'] || false
149
- end
150
- tag_order = options[:tag_order] || view['tag_order']&.normalize_order || :asc
151
-
152
- options[:times] = true if totals
122
+ section = options[:section] || Doing.setting('current_section')
123
+ order = options[:order]&.normalize_order || :asc
124
+ totals = options[:totals] || false
125
+ tag_order = options[:tag_order]&.normalize_order || :asc
153
126
  output_format = options[:output]&.downcase || 'template'
154
127
 
155
- options[:sort_tags] = if options[:tag_sort]
156
- options[:tag_sort]
157
- elsif view.key?('tag_sort')
158
- view['tag_sort'].normalize_tag_sort
159
- else
160
- false
161
- end
162
-
163
- %w[before after from duration].each { |k| options[k.to_sym] = view[k] if view.key?(k) && !options[k.to_sym] }
128
+ options[:times] = true if totals
164
129
 
130
+ options.rename_key(:tag_sort, :sort_tags)
131
+ options[:sort_tags] ||= :name
132
+ options.rename_key(:date_format, :format)
133
+ options.rename_key(:color, :highlight)
165
134
  search = nil
166
135
 
167
136
  if options[:search]
@@ -172,12 +141,8 @@ command :view do |c|
172
141
  options[:age] ||= :newest
173
142
 
174
143
  opts = options.clone
175
- opts[:age] = options[:age]
176
- opts[:count] = count
177
- opts[:format] = date_format
178
- opts[:highlight] = options[:color]
179
- opts[:hilite] = options[:hilite]
180
- opts[:only_timed] = only_timed
144
+
145
+ opts[:count] ||= 10
181
146
  opts[:order] = order
182
147
  opts[:output] = options[:interactive] ? nil : options[:output]
183
148
  opts[:output] = output_format
@@ -186,8 +151,6 @@ command :view do |c|
186
151
  opts[:section] = section
187
152
  opts[:tag_filter] = tag_filter
188
153
  opts[:tag_order] = tag_order
189
- opts[:tags_color] = tags_color
190
- opts[:template] = template
191
154
  opts[:totals] = totals
192
155
  opts[:view_template] = title
193
156
 
@@ -1,11 +1,108 @@
1
1
  # @@views
2
- desc 'List available custom views'
2
+ desc 'List available custom views. Specify view names to see YAML configurations.'
3
+ arg_name 'NAME(S)', optional: true
3
4
  command :views do |c|
5
+ c.example 'doing views', desc: 'list all views'
6
+ c.example 'doing views -c', desc: 'list views in column, ideal for shell completion'
7
+ c.example 'doing views color', desc: 'dump the YAML for a single view'
8
+ c.example 'doing views -e color', desc: 'edit the YAML configuration for a single view'
9
+ c.example 'doing views -e -o json color finished', desc: 'edit multiple view configs as JSON'
10
+
4
11
  c.desc 'List in single column'
5
- c.switch %i[c column], default_value: false
12
+ c.switch %i[c column], default_value: false, negatable: false
13
+
14
+ c.desc 'Open YAML for view in editor (requires argument)'
15
+ c.switch %i[e editor], negatable: false
16
+
17
+ c.desc 'Output/edit view in alternative format (json, yaml)'
18
+ c.arg_name 'FORMAT'
19
+ c.flag %i[o output], must_match: /^[jy]/i, default_value: 'yaml'
20
+
21
+ c.desc 'Delete view config'
22
+ c.switch %i[r remove], negatable: false
23
+
24
+ c.action do |_global_options, options, args|
25
+ cmd = Doing::ViewsCommand.new(options, args, @wwid)
26
+
27
+ if args.count.positive?
28
+ if options[:remove]
29
+ cmd.remove_views
30
+ elsif options[:editor]
31
+ cmd.edit_views
32
+ else
33
+ cmd.output_views
34
+ end
35
+ else
36
+ cmd.list_views
37
+ end
38
+ end
39
+ end
40
+
41
+ module Doing
42
+ # views Command
43
+ class ViewsCommand
44
+ def initialize(options, args, wwid)
45
+ @options = options
46
+ @args = args
47
+ @wwid = wwid
48
+
49
+ @views = {}
50
+ args.each do |v|
51
+ view = @wwid.get_view(v)
52
+ raise InvalidArgument, 'Unrecognized view' unless view
53
+
54
+ @views[v] = view if view
55
+ end
56
+ end
57
+
58
+ def list_views
59
+ joiner = @options[:column] ? "\n" : "\t"
60
+ print @wwid.views.join(joiner)
61
+ end
62
+
63
+ def save_view(view, res)
64
+ val = if res.nil? || !res.key?(view) || res[view]&.empty?
65
+ nil
66
+ else
67
+ res[view]
68
+ end
69
+
70
+ Doing.set("views.#{view}", val)
71
+ end
72
+
73
+ def remove_views
74
+ @args.each do |v|
75
+ Doing.set("views.#{v}", nil)
76
+ end
77
+
78
+ save_config
79
+ end
80
+
81
+ def edit_views
82
+ res = if @options[:output] =~ /^j/i
83
+ JSON.parse(@wwid.fork_editor(JSON.pretty_generate(@views), message: nil))
84
+ else
85
+ YAML.safe_load(@wwid.fork_editor(YAML.dump(@views), message: nil))
86
+ end
87
+ @args.each do |v|
88
+ save_view(v, res)
89
+ end
90
+ save_config
91
+ end
92
+
93
+ def output_views
94
+ out = if @options[:output] =~ /^j/i
95
+ JSON.pretty_generate(@views)
96
+ else
97
+ YAML.dump(@views)
98
+ end
99
+
100
+ Doing::Pager.page out
101
+ end
6
102
 
7
- c.action do |_global_options, options, _args|
8
- joiner = options[:column] ? "\n" : "\t"
9
- print @wwid.views.join(joiner)
103
+ def save_config
104
+ Doing::Util.write_to_file(Doing.config.config_file, YAML.dump(Doing.settings), backup: true)
105
+ Doing.logger.warn('Config:', "#{Doing.config.config_file} updated")
106
+ end
10
107
  end
11
108
  end