doing 2.1.22 → 2.1.26

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/.yardoc/checksums +17 -14
  3. data/.yardoc/object_types +0 -0
  4. data/.yardoc/objects/root.dat +0 -0
  5. data/CHANGELOG.md +323 -111
  6. data/Gemfile.lock +1 -1
  7. data/README.md +1 -1
  8. data/Rakefile +2 -1
  9. data/bin/commands/add_section.rb +13 -0
  10. data/bin/commands/again.rb +99 -0
  11. data/bin/commands/archive.rb +96 -0
  12. data/bin/commands/cancel.rb +102 -0
  13. data/bin/commands/changes.rb +42 -0
  14. data/bin/commands/choose.rb +9 -0
  15. data/bin/commands/colors.rb +19 -0
  16. data/bin/commands/commands.rb +87 -0
  17. data/bin/commands/commands_accepting.rb +25 -0
  18. data/bin/commands/completion.rb +24 -0
  19. data/bin/commands/config.rb +245 -0
  20. data/bin/commands/done.rb +249 -0
  21. data/bin/commands/finish.rb +149 -0
  22. data/bin/commands/flag.rb +126 -0
  23. data/bin/commands/grep.rb +124 -0
  24. data/bin/commands/import.rb +101 -0
  25. data/bin/commands/install_fzf.rb +17 -0
  26. data/bin/commands/last.rb +114 -0
  27. data/bin/commands/meanwhile.rb +86 -0
  28. data/bin/commands/note.rb +130 -0
  29. data/bin/commands/now.rb +151 -0
  30. data/bin/commands/on.rb +66 -0
  31. data/bin/commands/open.rb +53 -0
  32. data/bin/commands/plugins.rb +23 -0
  33. data/bin/commands/recent.rb +78 -0
  34. data/bin/commands/redo.rb +22 -0
  35. data/bin/commands/reset.rb +106 -0
  36. data/bin/commands/rotate.rb +73 -0
  37. data/bin/commands/sections.rb +11 -0
  38. data/bin/commands/select.rb +123 -0
  39. data/bin/commands/show.rb +231 -0
  40. data/bin/commands/since.rb +64 -0
  41. data/bin/commands/tag.rb +179 -0
  42. data/bin/commands/tag_dir.rb +29 -0
  43. data/bin/commands/tags.rb +93 -0
  44. data/bin/commands/template.rb +61 -0
  45. data/bin/commands/today.rb +65 -0
  46. data/bin/commands/undo.rb +49 -0
  47. data/bin/commands/view.rb +238 -0
  48. data/bin/commands/views.rb +11 -0
  49. data/bin/commands/yesterday.rb +73 -0
  50. data/bin/doing +54 -3505
  51. data/docs/doc/Array.html +79 -11
  52. data/docs/doc/BooleanTermParser/Clause.html +5 -5
  53. data/docs/doc/BooleanTermParser/Operator.html +4 -4
  54. data/docs/doc/BooleanTermParser/Query.html +8 -8
  55. data/docs/doc/BooleanTermParser/QueryParser.html +2 -2
  56. data/docs/doc/BooleanTermParser/QueryTransformer.html +2 -2
  57. data/docs/doc/BooleanTermParser.html +1 -1
  58. data/docs/doc/Doing/Color.html +4 -4
  59. data/docs/doc/Doing/Completion.html +2 -2
  60. data/docs/doc/Doing/Configuration.html +17 -18
  61. data/docs/doc/Doing/Errors/DoingNoTraceError.html +2 -2
  62. data/docs/doc/Doing/Errors/DoingRuntimeError.html +2 -2
  63. data/docs/doc/Doing/Errors/DoingStandardError.html +2 -2
  64. data/docs/doc/Doing/Errors/EmptyInput.html +2 -2
  65. data/docs/doc/Doing/Errors/NoResults.html +2 -2
  66. data/docs/doc/Doing/Errors/PluginException.html +3 -3
  67. data/docs/doc/Doing/Errors/UserCancelled.html +2 -2
  68. data/docs/doc/Doing/Errors/WrongCommand.html +2 -2
  69. data/docs/doc/Doing/Errors.html +1 -1
  70. data/docs/doc/Doing/Hooks.html +6 -6
  71. data/docs/doc/Doing/Item.html +50 -16
  72. data/docs/doc/Doing/Items.html +10 -10
  73. data/docs/doc/Doing/LogAdapter.html +24 -24
  74. data/docs/doc/Doing/Note.html +7 -7
  75. data/docs/doc/Doing/Pager.html +4 -4
  76. data/docs/doc/Doing/Plugins.html +7 -7
  77. data/docs/doc/Doing/Prompt.html +59 -14
  78. data/docs/doc/Doing/Section.html +6 -6
  79. data/docs/doc/Doing/TemplateString.html +8 -8
  80. data/docs/doc/Doing/Types.html +206 -0
  81. data/docs/doc/Doing/Util/Backup.html +10 -10
  82. data/docs/doc/Doing/Util.html +16 -19
  83. data/docs/doc/Doing/WWID.html +65 -53
  84. data/docs/doc/Doing.html +3 -3
  85. data/docs/doc/FalseClass.html +201 -0
  86. data/docs/doc/GLI/Commands/Help.html +185 -0
  87. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +17 -17
  88. data/docs/doc/GLI/Commands.html +5 -3
  89. data/docs/doc/GLI.html +4 -2
  90. data/docs/doc/Hash.html +47 -21
  91. data/docs/doc/Numeric.html +5 -5
  92. data/docs/doc/Object.html +203 -0
  93. data/docs/doc/PhraseParser/Operator.html +4 -4
  94. data/docs/doc/PhraseParser/PhraseClause.html +5 -5
  95. data/docs/doc/PhraseParser/Query.html +10 -10
  96. data/docs/doc/PhraseParser/QueryParser.html +2 -2
  97. data/docs/doc/PhraseParser/QueryTransformer.html +2 -2
  98. data/docs/doc/PhraseParser/TermClause.html +5 -5
  99. data/docs/doc/PhraseParser.html +1 -1
  100. data/docs/doc/Status.html +7 -7
  101. data/docs/doc/String.html +144 -51
  102. data/docs/doc/Symbol.html +8 -8
  103. data/docs/doc/Time.html +6 -6
  104. data/docs/doc/TrueClass.html +201 -0
  105. data/docs/doc/_index.html +46 -16
  106. data/docs/doc/class_list.html +1 -1
  107. data/docs/doc/file.README.html +2 -2
  108. data/docs/doc/index.html +2 -2
  109. data/docs/doc/method_list.html +292 -212
  110. data/docs/doc/top-level-namespace.html +2 -2
  111. data/docs/index.md +1 -1
  112. data/doing.rdoc +178 -16
  113. data/example_plugin.rb +2 -2
  114. data/lib/completion/_doing.zsh +27 -27
  115. data/lib/completion/doing.bash +31 -20
  116. data/lib/completion/doing.fish +33 -11
  117. data/lib/doing/array.rb +2 -2
  118. data/lib/doing/changelog/change.rb +115 -0
  119. data/lib/doing/changelog/changes.rb +73 -0
  120. data/lib/doing/changelog/entry.rb +21 -0
  121. data/lib/doing/changelog/version.rb +97 -0
  122. data/lib/doing/changelog.rb +6 -0
  123. data/lib/doing/completion/fish_completion.rb +2 -1
  124. data/lib/doing/configuration.rb +20 -13
  125. data/lib/doing/good.rb +64 -0
  126. data/lib/doing/hash.rb +7 -2
  127. data/lib/doing/help_monkey_patch.rb +31 -0
  128. data/lib/doing/hooks.rb +8 -4
  129. data/lib/doing/item.rb +24 -35
  130. data/lib/doing/pager.rb +1 -0
  131. data/lib/doing/plugins/export/template_export.rb +1 -1
  132. data/lib/doing/plugins/import/calendar_import.rb +1 -1
  133. data/lib/doing/plugins/import/doing_import.rb +1 -1
  134. data/lib/doing/plugins/import/timing_import.rb +1 -1
  135. data/lib/doing/prompt.rb +8 -0
  136. data/lib/doing/string.rb +20 -11
  137. data/lib/doing/string_chronify.rb +1 -1
  138. data/lib/doing/template_string.rb +2 -2
  139. data/lib/doing/types.rb +3 -0
  140. data/lib/doing/util.rb +12 -11
  141. data/lib/doing/version.rb +1 -1
  142. data/lib/doing/wwid.rb +62 -37
  143. data/lib/doing.rb +2 -0
  144. data/lib/examples/commands/wiki.rb +6 -7
  145. data/lib/helpers/threaded_tests.rb +61 -71
  146. data/lib/helpers/threaded_tests_string.rb +50 -0
  147. metadata +56 -2
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- doing (2.1.22)
4
+ doing (2.1.26)
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)
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.21<!--END VER-->.
11
+ The current version of `doing` is <!--VER-->2.1.25<!--END VER-->.
12
12
 
13
13
  Find all of the documentation in the [doing wiki][wiki].
14
14
 
data/Rakefile CHANGED
@@ -77,10 +77,11 @@ task :dockertest, :version, :login do |_, args|
77
77
  file = 'Dockerfile'
78
78
  end
79
79
 
80
- exec "docker run -it #{img} /bin/bash -l" if args[:login]
81
80
 
82
81
  puts `docker build . --file #{file} -t #{img}`
83
82
 
83
+ exec "docker run -it #{img} /bin/bash -l" if args[:login]
84
+
84
85
  spinner = TTY::Spinner.new('[:spinner] Running tests ...', hide_cursor: true)
85
86
 
86
87
  spinner.auto_spin
@@ -0,0 +1,13 @@
1
+ # @@add_section
2
+ desc 'Add a new section to the "doing" file'
3
+ arg_name 'SECTION_NAME'
4
+ command :add_section do |c|
5
+ c.example 'doing add_section Ideas', desc: 'Add a section called Ideas to the doing file'
6
+
7
+ c.action do |_global_options, _options, args|
8
+ raise InvalidArgument, "Section #{args[0]} already exists" if @wwid.sections.include?(args[0])
9
+
10
+ @wwid.content.add_section(args.join(' ').cap_first, log: true)
11
+ @wwid.write(@wwid.doing_file)
12
+ end
13
+ end
@@ -0,0 +1,99 @@
1
+ # @@again @@resume
2
+ desc 'Repeat last entry as new entry'
3
+ long_desc 'This command is designed to allow multiple time intervals to be created for an entry by duplicating it with a new start (and end, eventually) time'
4
+ command %i[again resume] do |c|
5
+ c.example 'doing resume', desc: 'Duplicate the most recent entry with a new start time, removing any @done tag'
6
+ c.example 'doing again', desc: 'again is an alias for resume'
7
+ c.example 'doing resume --editor', desc: 'Repeat the last entry, opening the new entry in the default editor'
8
+ c.example 'doing resume --tag project1 --in Projects', desc: 'Repeat the last entry tagged @project1, creating the new entry in the Projects section'
9
+ c.example 'doing resume --interactive', desc: 'Select the entry to repeat from a menu'
10
+
11
+ c.desc 'Get last entry from a specific section'
12
+ c.arg_name 'NAME'
13
+ c.flag %i[s section], default_value: 'All'
14
+
15
+ c.desc 'Add new entry to section (default: same section as repeated entry)'
16
+ c.arg_name 'SECTION_NAME'
17
+ c.flag [:in]
18
+
19
+ c.desc 'Backdate start date by interval or set to time [4pm|20m|2h|"yesterday noon"]'
20
+ c.arg_name 'DATE_STRING'
21
+ c.flag %i[b back started], type: DateBeginString
22
+
23
+ c.desc 'Repeat last entry matching tags. Combine multiple tags with a comma. Wildcards allowed (*, ?)'
24
+ c.arg_name 'TAG'
25
+ c.flag [:tag], type: TagArray
26
+
27
+ c.desc 'Repeat last entry matching search. Surround with
28
+ slashes for regex (e.g. "/query/"), start with a single quote for exact match ("\'query").'
29
+ c.arg_name 'QUERY'
30
+ c.flag [:search]
31
+
32
+ c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
33
+ c.arg_name 'QUERY'
34
+ c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
35
+
36
+ # c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
37
+ # c.switch [:fuzzy], default_value: false, negatable: false
38
+
39
+ c.desc 'Force exact search string matching (case sensitive)'
40
+ c.switch %i[x exact], default_value: @config.exact_match?, negatable: @config.exact_match?
41
+
42
+ c.desc 'Resume items that *don\'t* match search/tag filters'
43
+ c.switch [:not], default_value: false, negatable: false
44
+
45
+ c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
46
+ c.arg_name 'TYPE'
47
+ c.flag [:case], must_match: /^[csi]/, default_value: @settings.dig('search', 'case')
48
+
49
+ c.desc 'Boolean used to combine multiple tags. Use PATTERN to parse + and - as booleans'
50
+ c.arg_name 'BOOLEAN'
51
+ c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
52
+
53
+ c.desc "Edit duplicated entry with #{Doing::Util.default_editor} before adding"
54
+ c.switch %i[e editor], negatable: false, default_value: false
55
+
56
+ c.desc 'Add a note'
57
+ c.arg_name 'TEXT'
58
+ c.flag %i[n note]
59
+
60
+ c.desc 'Prompt for note via multi-line input'
61
+ c.switch %i[ask], negatable: false, default_value: false
62
+
63
+ c.desc 'Select item to resume from a menu of matching entries'
64
+ c.switch %i[i interactive], negatable: false, default_value: false
65
+
66
+ c.action do |_global_options, options, _args|
67
+ options[:fuzzy] = false
68
+ tags = options[:tag].nil? ? [] : options[:tag]
69
+
70
+ options[:case] = options[:case].normalize_case
71
+
72
+ if options[:search]
73
+ search = options[:search]
74
+ search.sub!(/^'?/, "'") if options[:exact]
75
+ options[:search] = search
76
+ end
77
+
78
+ if options[:back]
79
+ date = options[:back]
80
+ raise InvalidTimeExpression, 'Unable to parse date string for --back' if date.nil?
81
+ else
82
+ date = Time.now
83
+ end
84
+
85
+ note = Doing::Note.new(options[:note])
86
+ note.add(Doing::Prompt.read_lines(prompt: 'Add a note')) if options[:ask]
87
+
88
+ options[:note] = note
89
+
90
+ opts = options.clone
91
+
92
+ opts[:tag] = tags
93
+ opts[:tag_bool] = options[:bool].normalize_bool
94
+ opts[:interactive] = options[:interactive]
95
+ opts[:date] = date
96
+
97
+ @wwid.repeat_last(opts)
98
+ end
99
+ end
@@ -0,0 +1,96 @@
1
+ # @@archive @@move
2
+ desc 'Move entries between sections'
3
+ long_desc %(Argument can be a section name to move all entries from a section,
4
+ or start with an "@" to move entries matching a tag.
5
+
6
+ Default with no argument moves items from the "#{@settings['current_section']}" section to Archive.)
7
+ arg_name 'SECTION_OR_TAG'
8
+ default_value @settings['current_section']
9
+ command %i[archive move] do |c|
10
+ c.example 'doing archive Currently', desc: 'Move all entries in the Currently section to Archive section'
11
+ c.example 'doing archive @done', desc: 'Move all entries tagged @done to Archive'
12
+ c.example 'doing archive --to Later @project1', desc: 'Move all entries tagged @project1 to Later section'
13
+ c.example 'doing move Later --tag project1 --to Currently', desc: 'Move entries in Later tagged @project1 to Currently (move is an alias for archive)'
14
+
15
+ c.desc 'How many items to keep (ignored if archiving by tag or search)'
16
+ c.arg_name 'X'
17
+ c.flag %i[k keep], must_match: /^\d+$/, type: Integer
18
+
19
+ c.desc 'Move entries to'
20
+ c.arg_name 'SECTION_NAME'
21
+ c.flag %i[t to], default_value: 'Archive'
22
+
23
+ c.desc 'Label moved items with @from(SECTION_NAME)'
24
+ c.switch [:label], default_value: true, negatable: true
25
+
26
+ c.desc 'Tag filter, combine multiple tags with a comma. Wildcards allowed (*, ?). Added for compatibility with other commands'
27
+ c.arg_name 'TAG'
28
+ c.flag [:tag], type: TagArray
29
+
30
+ c.desc 'Tag boolean (AND|OR|NOT). Use PATTERN to parse + and - as booleans'
31
+ c.arg_name 'BOOLEAN'
32
+ c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
33
+
34
+ c.desc 'Search filter'
35
+ c.arg_name 'QUERY'
36
+ c.flag [:search]
37
+
38
+ c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
39
+ c.arg_name 'QUERY'
40
+ c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
41
+
42
+ # c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
43
+ # c.switch [:fuzzy], default_value: false, negatable: false
44
+
45
+ c.desc 'Force exact search string matching (case sensitive)'
46
+ c.switch %i[x exact], default_value: @config.exact_match?, negatable: @config.exact_match?
47
+
48
+ c.desc 'Show items that *don\'t* match search string'
49
+ c.switch [:not], default_value: false, negatable: false
50
+
51
+ c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
52
+ c.arg_name 'TYPE'
53
+ c.flag [:case], must_match: /^[csi]/, default_value: @settings.dig('search', 'case')
54
+
55
+ c.desc 'Archive entries older than date
56
+ (Flexible date format, e.g. 1/27/2021, 2020-07-19, or Monday 3pm)'
57
+ c.arg_name 'DATE_STRING'
58
+ c.flag [:before], type: DateEndString
59
+
60
+ c.action do |_global_options, options, args|
61
+ options[:fuzzy] = false
62
+ if args.empty?
63
+ section = @settings['current_section']
64
+ tags = []
65
+ elsif args[0] =~ /^all/i
66
+ section = 'all'
67
+ elsif args[0] =~ /^@\S+/
68
+ section = 'all'
69
+ tags = args.map { |t| t.sub(/^@/, '').strip }
70
+ else
71
+ section = args[0].cap_first
72
+ tags = args.length > 1 ? args[1..].map { |t| t.sub(/^@/, '').strip } : []
73
+ end
74
+
75
+ raise InvalidArgument, '--keep and --count can not be used together' if options[:keep] && options[:count]
76
+
77
+ tags.concat(options[:tag]) if options[:tag]
78
+
79
+ search = nil
80
+
81
+ options[:case] = options[:case].normalize_case
82
+
83
+ if options[:search]
84
+ search = options[:search]
85
+ search.sub!(/^'?/, "'") if options[:exact]
86
+ end
87
+
88
+ opts = options.clone
89
+ opts[:search] = search
90
+ opts[:bool] = options[:bool].normalize_bool
91
+ opts[:destination] = options[:to]
92
+ opts[:tags] = tags
93
+
94
+ @wwid.archive(section, opts)
95
+ end
96
+ end
@@ -0,0 +1,102 @@
1
+ # @@cancel
2
+ desc 'End last X entries with no time tracked'
3
+ long_desc 'Adds @done tag without datestamp so no elapsed time is recorded. Alias for `doing finish --no-date`'
4
+ arg_name 'COUNT'
5
+ command :cancel do |c|
6
+ c.example 'doing cancel', desc: 'Cancel the last entry'
7
+ c.example 'doing cancel --tag project1 -u 5', desc: 'Cancel the last 5 unfinished entries containing @project1'
8
+
9
+ c.desc 'Archive entries'
10
+ c.switch %i[a archive], negatable: false, default_value: false
11
+
12
+ c.desc 'Section'
13
+ c.arg_name 'NAME'
14
+ c.flag %i[s section]
15
+
16
+ c.desc 'Cancel the last X entries containing TAG. Separate multiple tags with comma (--tag=tag1,tag2). Wildcards allowed (*, ?)'
17
+ c.arg_name 'TAG'
18
+ c.flag [:tag], type: TagArray
19
+
20
+ c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans'
21
+ c.arg_name 'BOOLEAN'
22
+ c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
23
+
24
+ c.desc 'Cancel the last X entries matching search filter, surround with slashes for regex (e.g. "/query.*/"), start with single quote for exact match ("\'query")'
25
+ c.arg_name 'QUERY'
26
+ c.flag [:search]
27
+
28
+ c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
29
+ c.arg_name 'QUERY'
30
+ c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
31
+
32
+ # c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
33
+ # c.switch [:fuzzy], default_value: false, negatable: false
34
+
35
+ c.desc 'Force exact search string matching (case sensitive)'
36
+ c.switch %i[x exact], default_value: @config.exact_match?, negatable: @config.exact_match?
37
+
38
+ c.desc 'Finish items that *don\'t* match search/tag filters'
39
+ c.switch [:not], default_value: false, negatable: false
40
+
41
+ c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
42
+ c.arg_name 'TYPE'
43
+ c.flag [:case], must_match: /^[csi]/, default_value: @settings.dig('search', 'case')
44
+
45
+ c.desc 'Cancel last entry (or entries) not already marked @done'
46
+ c.switch %i[u unfinished], negatable: false, default_value: false
47
+
48
+ c.desc 'Select item(s) to cancel from a menu of matching entries'
49
+ c.switch %i[i interactive], negatable: false, default_value: false
50
+
51
+ c.action do |_global_options, options, args|
52
+ options[:fuzzy] = false
53
+ if options[:section]
54
+ section = @wwid.guess_section(options[:section]) || options[:section].cap_first
55
+ else
56
+ section = @settings['current_section']
57
+ end
58
+
59
+ if options[:tag].nil?
60
+ tags = []
61
+ else
62
+ tags = options[:tag]
63
+ end
64
+
65
+ raise InvalidArgument, 'Only one argument allowed' if args.length > 1
66
+
67
+ raise InvalidArgument, 'Invalid argument (specify number of recent items to mark @done)' unless args.empty? || args[0] =~ /\d+/
68
+
69
+ if options[:interactive]
70
+ count = 0
71
+ else
72
+ count = args[0] ? args[0].to_i : 1
73
+ end
74
+
75
+ search = nil
76
+
77
+ if options[:search]
78
+ search = options[:search]
79
+ search.sub!(/^'?/, "'") if options[:exact]
80
+ end
81
+
82
+ opts = {
83
+ archive: options[:archive],
84
+ case: options[:case].normalize_case,
85
+ count: count,
86
+ date: false,
87
+ fuzzy: options[:fuzzy],
88
+ interactive: options[:interactive],
89
+ not: options[:not],
90
+ search: search,
91
+ section: section,
92
+ sequential: false,
93
+ tag: tags,
94
+ tag_bool: options[:bool].normalize_bool,
95
+ tags: ['done'],
96
+ unfinished: options[:unfinished],
97
+ val: options[:val]
98
+ }
99
+
100
+ @wwid.tag_last(opts)
101
+ end
102
+ end
@@ -0,0 +1,42 @@
1
+ # @@changelog @@changes
2
+ desc 'List recent changes in Doing'
3
+ long_desc %(Display a formatted list of changes in recent versions.
4
+
5
+ Without flags, displays only the most recent version.
6
+ Use --lookup or --all for history.)
7
+ command %i[changes changelog] do |c|
8
+ c.desc 'Display all versions'
9
+ c.switch %i[a all], default_value: false, negatable: false
10
+
11
+ c.desc %(Look up a specific version. Specify versions as "MAJ.MIN.PATCH", MIN
12
+ and PATCH are optional. Use > or < to see all changes since or prior
13
+ to a version.)
14
+ c.arg_name 'VERSION'
15
+ c.flag %i[l lookup], must_match: /^(?:(?:(?:[<>=]|p(?:rior)|b(?:efore)|o(?:lder)|s(?:ince)|a(?:fter)|n(?:ewer))? *[\d.*?]+ *)+|(?:[\d.]+ *-+ *[\d.]+))$/
16
+
17
+ c.desc %(Show changelogs matching search terms (uses pattern-based searching).
18
+ Add slashes to search with regular expressions, e.g. `--search "/output.*flag/"`)
19
+ c.flag %i[s search]
20
+
21
+ c.example 'doing changes', desc: 'View changes in the current version'
22
+ c.example 'doing changes --all', desc: 'See the entire changelog'
23
+ c.example 'doing changes --lookup 2.0.21', desc: 'See changes from version 2.0.21'
24
+ c.example 'doing changes --lookup "> 2.1"', desc: 'See all changes since 2.1.0'
25
+ c.example 'doing changes --search "tags +bool"', desc: 'See all changes containing "tags" and "bool"'
26
+ c.example 'doing changes -l "> 2.1" -s "pattern"', desc: 'Lookup and search can be combined'
27
+
28
+
29
+ c.action do |_global_options, options, args|
30
+ cl = Doing::Changes.new(lookup: options[:lookup], search: options[:search])
31
+
32
+ content = if options[:all] || options[:search] || options[:lookup]
33
+ cl.to_s
34
+ else
35
+ cl.latest
36
+ end
37
+
38
+ parsed = TTY::Markdown.parse(content, width: 80, symbols: {override: {bullet: "•"}})
39
+ Doing::Pager.paginate = true
40
+ Doing::Pager.page parsed
41
+ end
42
+ end
@@ -0,0 +1,9 @@
1
+ # @@choose
2
+ desc 'Select a section to display from a menu'
3
+ command :choose do |c|
4
+ c.action do |_global_options, _options, _args|
5
+ section = @wwid.choose_section
6
+
7
+ Doing::Pager.page @wwid.list_section({ section: section.cap_first, count: 0 }) if section
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ # @@colors
2
+ desc 'List available color variables for configuration templates and views'
3
+ command :colors do |c|
4
+ c.action do |_global_options, _options, _args|
5
+ bgs = []
6
+ fgs = []
7
+ @colors::attributes.each do |color|
8
+ if color.to_s =~ /bg/
9
+ bgs.push("#{@colors.send(color, " ")}#{@colors.default} <-- #{color.to_s}")
10
+ else
11
+ fgs.push("#{@colors.send(color, "XXXX")}#{@colors.default} <-- #{color.to_s}")
12
+ end
13
+ end
14
+ out = []
15
+ out << fgs.join("\n")
16
+ out << bgs.join("\n")
17
+ Doing::Pager.page out.join("\n")
18
+ end
19
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @@commands
4
+ desc 'Enable and disable Doing commands'
5
+ command :commands do |c|
6
+ c.example 'doing commands add', desc: 'Get a menu of available commands'
7
+ c.example 'doing commands add COMMAND', desc: 'Specify a command to enable'
8
+ c.example 'doing commands remove COMMAND', desc: 'Specify a command to disable'
9
+
10
+ c.default_command :add
11
+
12
+ # @@commands.enable
13
+ c.desc 'Enable Doing commands'
14
+ c.long_desc 'Run without arguments to select commands from a list.'
15
+ c.arg_name 'COMMAND [COMMAND...]'
16
+ c.command %i[add enable] do |add|
17
+ add.action do |_global, _options, args|
18
+ cfg = @settings
19
+ custom_dir = @settings.dig('plugins', 'command_path')
20
+
21
+ available = cfg['disabled_commands']
22
+ raise UserCancelled, 'No commands available to enable' unless args.good? || available.good?
23
+
24
+ to_enable = if args.good?
25
+ args
26
+ else
27
+ Doing::Prompt.choose_from(available,
28
+ prompt: 'Select commands to enable',
29
+ multiple: true,
30
+ sorted: true).strip.split("\n")
31
+ end
32
+ to_enable.each do |cmd|
33
+ default_command = File.join(File.dirname(__FILE__), "#{cmd}.rb")
34
+ custom_command = File.join(File.expand_path(custom_dir), "#{cmd}.rb")
35
+ unless File.exist?(default_command) || File.exist?(custom_command)
36
+ raise InvalidArgument, "Command #{cmd} not found"
37
+ end
38
+
39
+ raise InvalidArgument, "Command #{cmd} is not disabled" unless available.include?(cmd)
40
+
41
+ available.delete(cmd)
42
+ end
43
+
44
+ cfg.deep_set(['disabled_commands'], available)
45
+
46
+ Doing::Util.write_to_file(@config.config_file, YAML.dump(cfg), backup: true)
47
+ Doing.logger.warn('Config:', "#{@config.config_file} updated")
48
+ end
49
+ end
50
+
51
+ # @@commands.disable
52
+ c.desc 'Disable Doing commands'
53
+ c.command %i[remove disable] do |remove|
54
+ remove.action do |_global, _options, args|
55
+ available = Dir.glob(File.join(File.dirname(__FILE__), '*.rb')).map { |cmd| File.basename(cmd, '.rb') }
56
+ cfg = @settings
57
+ custom_dir = @settings.dig('plugins', 'command_path')
58
+ custom_commands = Dir.glob(File.join(File.expand_path(custom_dir), '*.rb'))
59
+ available.concat(custom_commands.map { |cmd| File.basename(cmd, '.rb') })
60
+ disabled = cfg['disabled_commands']
61
+ disabled.each { |cmd| available.delete(cmd) }
62
+ to_disable = if args.good?
63
+ args
64
+ else
65
+ Doing::Prompt.choose_from(available,
66
+ prompt: 'Select commands to enable',
67
+ multiple: true,
68
+ sorted: true).strip.split("\n")
69
+ end
70
+ to_disable.each do |cmd|
71
+ default_command = File.join(File.dirname(__FILE__), "#{cmd}.rb")
72
+ custom_command = File.join(File.expand_path(custom_dir), "#{cmd}.rb")
73
+ unless File.exist?(default_command) || File.exist?(custom_command)
74
+ raise InvalidArgument, "Command #{cmd} not found"
75
+
76
+ end
77
+
78
+ raise InvalidArgument, "Command #{cmd} is not enabled" unless available.include?(cmd)
79
+ end
80
+
81
+ cfg.deep_set(['disabled_commands'], disabled.concat(to_disable))
82
+
83
+ Doing::Util.write_to_file(@config.config_file, YAML.dump(cfg), backup: true)
84
+ Doing.logger.warn('Config:', "#{@config.config_file} updated")
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,25 @@
1
+ # @@commands_accepting
2
+ arg_name 'OPTION'
3
+ command :commands_accepting do |c|
4
+ c.desc 'Output in single column for completion'
5
+ c.switch %i[c column]
6
+
7
+ c.action do |g, o, a|
8
+ a.each do |option|
9
+ cmds = []
10
+ commands.each do |cmd, v|
11
+ v.flags.merge(v.switches).each do |n, flag|
12
+ if flag.name == option.to_sym || flag.aliases&.include?(option.to_sym)
13
+ cmds.push(cmd)
14
+ end
15
+ end
16
+ end
17
+
18
+ if o[:column]
19
+ puts cmds.sort
20
+ else
21
+ puts "Commands accepting --#{option}: #{cmds.sort.join(', ')}"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,24 @@
1
+ # @@completion
2
+ desc 'Generate shell completion scripts'
3
+ long_desc 'Generates the necessary scripts to add command line completion to various shells, so typing \'doing\' and hitting
4
+ tab will offer completions of subcommands and their options.'
5
+ command :completion do |c|
6
+ c.example 'doing completion', desc: 'Output zsh (default) to STDOUT'
7
+ c.example 'doing completion --type zsh --file ~/.zsh-completions/_doing.zsh', desc: 'Output zsh completions to file'
8
+ c.example 'doing completion --type fish --file ~/.config/fish/completions/doing.fish', desc: 'Output fish completions to file'
9
+ c.example 'doing completion --type bash --file ~/.bash_it/completion/enabled/doing.bash', desc: 'Output bash completions to file'
10
+
11
+ c.desc 'Shell to generate for (bash, zsh, fish)'
12
+ c.arg_name 'SHELL'
13
+ c.flag %i[t type], must_match: /^(?:[bzf](?:[ai]?sh)?|all)$/i, default_value: 'zsh'
14
+
15
+ c.desc 'File to write output to'
16
+ c.arg_name 'PATH'
17
+ c.flag %i[f file], default_value: 'STDOUT'
18
+
19
+ c.action do |_global_options, options, _args|
20
+ script_dir = File.join(File.dirname(__FILE__), '..', 'scripts')
21
+
22
+ Doing::Completion.generate_completion(type: options[:type], file: options[:file])
23
+ end
24
+ end