doing 2.1.19 → 2.1.24

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/.yardoc/checksums +19 -16
  3. data/.yardoc/object_types +0 -0
  4. data/.yardoc/objects/root.dat +0 -0
  5. data/CHANGELOG.md +70 -0
  6. data/Gemfile.lock +11 -11
  7. data/README.md +1 -1
  8. data/Rakefile +12 -4
  9. data/bin/doing +297 -234
  10. data/docs/doc/Array.html +7 -30
  11. data/docs/doc/BooleanTermParser/Clause.html +3 -3
  12. data/docs/doc/BooleanTermParser/Operator.html +3 -3
  13. data/docs/doc/BooleanTermParser/Query.html +3 -3
  14. data/docs/doc/BooleanTermParser/QueryParser.html +3 -3
  15. data/docs/doc/BooleanTermParser/QueryTransformer.html +3 -3
  16. data/docs/doc/BooleanTermParser.html +3 -3
  17. data/docs/doc/Doing/Color.html +3 -3
  18. data/docs/doc/Doing/Completion.html +3 -3
  19. data/docs/doc/Doing/Configuration.html +6 -5
  20. data/docs/doc/Doing/Errors/DoingNoTraceError.html +3 -3
  21. data/docs/doc/Doing/Errors/DoingRuntimeError.html +3 -3
  22. data/docs/doc/Doing/Errors/DoingStandardError.html +3 -3
  23. data/docs/doc/Doing/Errors/EmptyInput.html +3 -3
  24. data/docs/doc/Doing/Errors/NoResults.html +3 -3
  25. data/docs/doc/Doing/Errors/PluginException.html +3 -3
  26. data/docs/doc/Doing/Errors/UserCancelled.html +3 -3
  27. data/docs/doc/Doing/Errors/WrongCommand.html +3 -3
  28. data/docs/doc/Doing/Errors.html +3 -3
  29. data/docs/doc/Doing/Hooks.html +3 -3
  30. data/docs/doc/Doing/Item.html +3 -3
  31. data/docs/doc/Doing/Items.html +3 -3
  32. data/docs/doc/Doing/LogAdapter.html +3 -3
  33. data/docs/doc/Doing/Note.html +3 -3
  34. data/docs/doc/Doing/Pager.html +3 -3
  35. data/docs/doc/Doing/Plugins.html +3 -3
  36. data/docs/doc/Doing/Prompt.html +7 -7
  37. data/docs/doc/Doing/Section.html +3 -3
  38. data/docs/doc/Doing/TemplateString.html +4 -4
  39. data/docs/doc/Doing/Types.html +201 -0
  40. data/docs/doc/Doing/Util/Backup.html +3 -3
  41. data/docs/doc/Doing/Util.html +4 -7
  42. data/docs/doc/Doing/WWID.html +66 -8
  43. data/docs/doc/Doing.html +6 -6
  44. data/docs/doc/GLI/Commands/Help.html +185 -0
  45. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +3 -3
  46. data/docs/doc/GLI/Commands.html +7 -5
  47. data/docs/doc/GLI.html +6 -4
  48. data/docs/doc/Hash.html +80 -16
  49. data/docs/doc/Numeric.html +3 -3
  50. data/docs/doc/PhraseParser/Operator.html +3 -3
  51. data/docs/doc/PhraseParser/PhraseClause.html +3 -3
  52. data/docs/doc/PhraseParser/Query.html +3 -3
  53. data/docs/doc/PhraseParser/QueryParser.html +3 -3
  54. data/docs/doc/PhraseParser/QueryTransformer.html +3 -3
  55. data/docs/doc/PhraseParser/TermClause.html +3 -3
  56. data/docs/doc/PhraseParser.html +3 -3
  57. data/docs/doc/Status.html +3 -3
  58. data/docs/doc/String.html +195 -26
  59. data/docs/doc/Symbol.html +3 -3
  60. data/docs/doc/Time.html +3 -3
  61. data/docs/doc/_index.html +22 -8
  62. data/docs/doc/class_list.html +1 -1
  63. data/docs/doc/file.README.html +4 -4
  64. data/docs/doc/frames.html +1 -1
  65. data/docs/doc/index.html +4 -4
  66. data/docs/doc/method_list.html +334 -270
  67. data/docs/doc/top-level-namespace.html +3 -3
  68. data/docs/index.md +1 -1
  69. data/doing.gemspec +1 -1
  70. data/doing.rdoc +173 -15
  71. data/lib/completion/_doing.zsh +20 -20
  72. data/lib/completion/doing.bash +37 -26
  73. data/lib/completion/doing.fish +116 -17
  74. data/lib/doing/array.rb +5 -4
  75. data/lib/doing/array_chronify.rb +4 -3
  76. data/lib/doing/changelog/change.rb +115 -0
  77. data/lib/doing/changelog/changes.rb +73 -0
  78. data/lib/doing/changelog/entry.rb +21 -0
  79. data/lib/doing/changelog/version.rb +97 -0
  80. data/lib/doing/changelog.rb +6 -0
  81. data/lib/doing/completion/fish_completion.rb +82 -12
  82. data/lib/doing/configuration.rb +17 -8
  83. data/lib/doing/hash.rb +25 -6
  84. data/lib/doing/help_monkey_patch.rb +31 -0
  85. data/lib/doing/hooks.rb +5 -1
  86. data/lib/doing/item.rb +10 -25
  87. data/lib/doing/items.rb +3 -1
  88. data/lib/doing/log_adapter.rb +1 -1
  89. data/lib/doing/pager.rb +2 -2
  90. data/lib/doing/plugins/export/dayone_export.rb +1 -1
  91. data/lib/doing/plugins/export/markdown_export.rb +1 -1
  92. data/lib/doing/plugins/export/template_export.rb +9 -3
  93. data/lib/doing/prompt.rb +4 -2
  94. data/lib/doing/string.rb +40 -11
  95. data/lib/doing/string_chronify.rb +56 -18
  96. data/lib/doing/template_string.rb +7 -0
  97. data/lib/doing/types.rb +25 -0
  98. data/lib/doing/util.rb +2 -1
  99. data/lib/doing/version.rb +1 -1
  100. data/lib/doing/wwid.rb +91 -67
  101. data/lib/doing.rb +2 -0
  102. data/lib/examples/commands/later.rb +32 -0
  103. data/lib/helpers/threaded_tests.rb +286 -0
  104. metadata +17 -6
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doing
4
+ # A collection of Changes
5
+ class Changes
6
+ attr_reader :changes
7
+
8
+ def initialize(lookup: nil, search: nil)
9
+ changelog = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'CHANGELOG.md'))
10
+ raise 'Error locating changelog' unless File.exist?(changelog)
11
+
12
+ @content = IO.read(changelog)
13
+ parse_changes(lookup, search)
14
+ end
15
+
16
+ def latest
17
+ @changes[0].to_s.force_encoding('utf-8')
18
+ end
19
+
20
+ def to_s
21
+ @changes.map(&:to_s).join("\n\n").force_encoding('utf-8')
22
+ end
23
+
24
+ private
25
+
26
+ def parse_changes(lookup, search)
27
+ change_rx = /(?<=\n|\A)### (\d+\.\d+\.\d+(?:\w+)?)(.*?)(?=\n### |\Z)/m
28
+ @changes = @content.scan(change_rx).each_with_object([]) do |m, a|
29
+ next if m[0].nil? || m[1].nil?
30
+
31
+ a << Change.new(m[0], m[1].strip)
32
+ end
33
+
34
+ lookup(lookup) unless lookup.nil?
35
+ search(search) unless search.nil?
36
+ end
37
+
38
+ def lookup(lookup_version)
39
+ range = []
40
+
41
+ if lookup_version =~ /([\d.]+) *-+ *([\d.]+)/
42
+ m = Regexp.last_match
43
+ lookup("> #{m[1]}")
44
+ lookup("< #{m[2]}")
45
+ elsif lookup_version.scan(/[<>]/).count > 1
46
+ params = lookup_version.scan(/[<>] [\d.]+/)
47
+ params.each { |query| lookup(query) }
48
+ else
49
+ comp = case lookup_version
50
+ when /(<|prior|before|older)/
51
+ :older
52
+ when />|since|after|newer/
53
+ :newer
54
+ else
55
+ :equal
56
+ end
57
+ version = Version.new(lookup_version)
58
+
59
+ @changes.select! do |change|
60
+ change.version.compare(version, comp)
61
+ end
62
+ end
63
+ end
64
+
65
+ def search(query)
66
+ @changes.map do |c|
67
+ c.entries = c.search_entries(query)
68
+ end
69
+
70
+ @changes.delete_if { |c| c.nil? || c.entries.nil? }
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doing
4
+ # An individual changelog item
5
+ class Entry
6
+ attr_reader :type, :string
7
+
8
+ def initialize(string, type)
9
+ @string = string
10
+ @type = type
11
+ end
12
+
13
+ def clean(string)
14
+ string.gsub(/\|/, '\|')
15
+ end
16
+
17
+ def to_s
18
+ "- #{clean(@string)}"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doing
4
+ # Semantic versioning
5
+ class Version
6
+ attr_reader :maj, :min, :patch
7
+
8
+ def initialize(string)
9
+ @maj, @min, @patch = version_to_a(string)
10
+ end
11
+
12
+ def version_to_a(string)
13
+ raise 'Version not a string' unless string.is_a?(String)
14
+
15
+ v = string.match(/(?<maj>\d+)(?:\.(?<min>[\d*?]+))?(?:\.(?<patch>[\d*?]+))?/)
16
+
17
+ raise 'Error parsing semantic version string' if v.nil?
18
+
19
+ maj = v['maj'].to_i
20
+ min = case v['min']
21
+ when /[*?]/
22
+ v['min'].sub(/(\d+)?[^\d]/, '\1\d+')
23
+ when /^[0-9]+$/
24
+ v['min'].to_i
25
+ end
26
+ pat = case v['patch']
27
+ when /[*?]/
28
+ v['patch'].sub(/(\d+)?[^\d]/, '\1\d+')
29
+ when /^[0-9]+$/
30
+ v['patch'].to_i
31
+ end
32
+ [maj, min, pat]
33
+ end
34
+
35
+ def wild?(val)
36
+ val.is_a?(String)
37
+ end
38
+
39
+
40
+ def compare(other, comp)
41
+ case comp
42
+ when :older
43
+ if @maj <= other.maj
44
+ if @maj < other.maj
45
+ true
46
+ elsif @maj == other.maj && (other.min.nil? || @min < other.min)
47
+ true
48
+ elsif @maj == other.maj && @min == other.min
49
+ other.patch.nil? ? false : @patch < other.patch
50
+ else
51
+ false
52
+ end
53
+ else
54
+ false
55
+ end
56
+ when :newer
57
+ if @maj >= other.maj
58
+ if @maj > other.maj
59
+ true
60
+ elsif @maj == other.maj && (other.min.nil? || @min > other.min)
61
+ true
62
+ elsif @maj == other.maj && @min == other.min
63
+ other.patch.nil? || @patch >= other.patch
64
+ else
65
+ false
66
+ end
67
+ else
68
+ false
69
+ end
70
+ when :equal
71
+ if @maj == other.maj
72
+ if other.min.nil?
73
+ true
74
+ elsif wild?(other.min)
75
+ @min.to_s =~ /^#{other.min}/ ? true : false
76
+ else
77
+ if @min == other.min
78
+ if other.patch.nil?
79
+ true
80
+ elsif wild?(other.patch)
81
+ @patch.to_s =~ /^#{other.patch}/ ? true : false
82
+ else
83
+ @patch == other.patch
84
+ end
85
+ else
86
+ false
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ def to_s
94
+ "#{@maj}.#{@min || 0}.#{@patch || 0}"
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'changelog/version'
4
+ require_relative 'changelog/entry'
5
+ require_relative 'changelog/change'
6
+ require_relative 'changelog/changes'
@@ -31,28 +31,89 @@ module Doing
31
31
  and return 0
32
32
  end
33
33
 
34
+ function __fish_doing_cache_timer_expired
35
+ set -l timer __fish_doing_cache_timer_$argv[1]
36
+ if not set -q $timer
37
+ set -g $timer (date '+%s')
38
+ end
39
+
40
+ if test (math (date '+%s') - $$timer) -gt $argv[2]
41
+ set -g $timer (date '+%s')
42
+ return 1
43
+ end
44
+
45
+ return 0
46
+ end
47
+
48
+ function __fish_doing_subcommands
49
+ if not set -q __fish_doing_subcommands_cache
50
+ or __fish_doing_cache_timer_expired subcommands 86400
51
+ set -g -a __fish_doing_subcommands_cache (doing help -c)
52
+ end
53
+ printf '%s\n' $__fish_doing_subcommands_cache
54
+ end
55
+
34
56
  function __fish_doing_complete_sections
35
- doing sections -c
57
+ if not set -q __fish_doing_sections_cache
58
+ or __fish_doing_cache_timer_expired sections 3600
59
+ set -g -a __fish_doing_sections_cache (doing sections -c)
60
+ end
61
+ printf '%s\n' $__fish_doing_sections_cache
62
+ __fish_doing_complete_show_tag
36
63
  end
37
64
 
38
65
  function __fish_doing_complete_views
39
- doing views -c
66
+ if not set -q __fish_doing_views_cache
67
+ or __fish_doing_cache_timer_expired views 3600
68
+ set -g -a __fish_doing_views_cache (doing views -c)
69
+ end
70
+ printf '%s\n' $__fish_doing_views_cache
40
71
  end
41
72
 
42
- function __fish_doing_subcommands
43
- doing help -c
73
+ function __fish_doing_export_plugin
74
+ if not set -q __fish_doing_export_plugin_cache
75
+ or __fish_doing_cache_timer_expired export_plugins 3600
76
+ set -g -a __fish_doing_export_plugin_cache (doing plugins --type export -c)
77
+ end
78
+ printf '%s\n' $__fish_doing_export_plugin_cache
79
+ end
80
+
81
+ function __fish_doing_import_plugin
82
+ if not set -q __fish_doing_import_plugin_cache
83
+ or __fish_doing_cache_timer_expired import_plugins 3600
84
+ set -g -a __fish_doing_import_plugin_cache (doing plugins --type import -c)
85
+ end
86
+ printf '%s\n' $__fish_doing_import_plugin_cache
87
+ end
88
+
89
+ function __fish_doing_complete_template
90
+ if not set -q __fish_doing_template_cache
91
+ or __fish_doing_cache_timer_expired template 3600
92
+ set -g -a __fish_doing_template_cache (doing template -c)
93
+ end
94
+ printf '%s\n' $__fish_doing_template_cache
44
95
  end
45
96
 
46
- function __fish_doing_export_plugins
47
- doing plugins --type export -c
97
+ function __fish_doing_complete_tag
98
+ if not set -q __fish_doing_tag_cache
99
+ or __fish_doing_cache_timer_expired tags 60
100
+ set -g -a __fish_doing_tag_cache (doing tags)
101
+ end
102
+ printf '%s\n' $__fish_doing_tag_cache
48
103
  end
49
104
 
50
- function __fish_doing_import_plugins
51
- doing plugins --type import -c
105
+ function __fish_doing_complete_show_tag
106
+ if not set -q __fish_doing_tag_cache
107
+ or __fish_doing_cache_timer_expired tags 60
108
+ set -g -a __fish_doing_tag_cache (doing tags)
109
+ end
110
+ printf '@%s\n' $__fish_doing_tag_cache
52
111
  end
53
112
 
54
- function __fish_doing_complete_templates
55
- doing template -c
113
+ function __fish_doing_complete_args
114
+ for cmd in (doing commands_accepting -c $argv[1])
115
+ complete -x -c doing -l $argv[1] -n "__fish_doing_using_command $cmd" -a "(__fish_doing_complete_$argv[1])"
116
+ end
56
117
  end
57
118
 
58
119
  complete -c doing -f
@@ -62,8 +123,17 @@ module Doing
62
123
  complete -f -c doing -n '__fish_doing_using_command view' -a '(__fish_doing_complete_views)'
63
124
  complete -f -c doing -n '__fish_doing_using_command template' -a '(__fish_doing_complete_templates)'
64
125
  complete -f -c doing -s t -l type -x -n '__fish_doing_using_command import' -a '(__fish_doing_import_plugins)'
126
+ complete -f -c doing -n '__fish_doing_using_command help' -a '(__fish_doing_subcommands)'
127
+
128
+ # complete -xc doing -n '__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from (doing help -c)' -a "(doing help -c)"
129
+
130
+ function __fish_doing_complete_args
131
+ for cmd in (doing commands_accepting -c $argv[1])
132
+ complete -x -c doing -l $argv[1] -n "__fish_doing_using_command $cmd" -a "(__fish_doing_complete_$argv[1])"
133
+ end
134
+ end
65
135
 
66
- complete -xc doing -n '__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from (doing help -c)' -a "(doing help -c)"
136
+ __fish_doing_complete_args tag
67
137
  EOFUNCTIONS
68
138
  end
69
139
 
@@ -161,7 +231,7 @@ module Doing
161
231
  end
162
232
 
163
233
  unless need_export.empty?
164
- out << "complete -f -c doing -s o -l output -x -n '__fish_doing_using_command #{need_export.join(' ')}' -a '(__fish_doing_export_plugins)'"
234
+ out << "complete -f -c doing -s o -l output -x -n '__fish_doing_using_command #{need_export.join(' ')}' -a '(__fish_doing_export_plugin)'"
165
235
  end
166
236
 
167
237
  unless need_bool.empty?
@@ -30,6 +30,7 @@ module Doing
30
30
  'command_path' => File.join(Util.user_home, '.config', 'doing', 'commands')
31
31
  },
32
32
  'doing_file' => '~/.local/share/doing/what_was_i_doing.md',
33
+ 'doing_file_sort' => 'desc',
33
34
  'backup_dir' => '~/.local/share/doing/doing_backup',
34
35
  'history_size' => 15,
35
36
  'current_section' => 'Currently',
@@ -159,7 +160,7 @@ module Doing
159
160
  def choose_config(create: false)
160
161
  return @config_file if @force_answer
161
162
 
162
- if @additional_configs.count.positive? || create
163
+ if @additional_configs&.count&.positive? || create
163
164
  choices = [@config_file].concat(@additional_configs)
164
165
  choices.push('Create a new .doingrc in the current directory') if create && !File.exist?('.doingrc')
165
166
  res = Doing::Prompt.choose_from(choices.uniq.sort.reverse,
@@ -189,7 +190,7 @@ module Doing
189
190
  ## matched, first match wins)
190
191
  ## @return [Array] ordered array of resolved keys
191
192
  ##
192
- def resolve_key_path(keypath, create: false)
193
+ def resolve_key_path(keypath, create: false, distance: 2)
193
194
  cfg = @settings
194
195
  real_path = []
195
196
  unless keypath =~ /^[.*]?$/
@@ -197,16 +198,24 @@ module Doing
197
198
  while paths.length.positive? && !cfg.nil?
198
199
  path = paths.shift
199
200
  new_cfg = nil
200
- cfg.each do |key, val|
201
- next unless key =~ path.to_rx(distance: 4)
202
201
 
203
- real_path << key
204
- new_cfg = val
205
- break
202
+ if cfg.is_a?(Hash)
203
+ matches = cfg.select { |key, val| key =~ path.to_rx(distance: distance) }
204
+ if matches.count.positive?
205
+ shortest = matches.keys.group_by(&:length).min.last[0]
206
+ real_path << shortest
207
+ new_cfg = matches[shortest]
208
+ end
209
+ else
210
+ new_cfg = cfg
206
211
  end
207
212
 
208
213
  if new_cfg.nil?
209
- return nil unless create
214
+ if distance < 5 && !create
215
+ return resolve_key_path(keypath, create: false, distance: distance + 1)
216
+ else
217
+ return nil unless create
218
+ end
210
219
 
211
220
  resolved = real_path.count.positive? ? "Resolved #{real_path.join('->')}, but " : ''
212
221
  Doing.logger.log_now(:warn, "#{resolved}#{path} is unknown")
data/lib/doing/hash.rb CHANGED
@@ -6,14 +6,32 @@ module Doing
6
6
  ##
7
7
  ## Freeze all values in a hash
8
8
  ##
9
- ## @return { description_of_the_return_value }
9
+ ## @return Hash with all values frozen
10
10
  ##
11
11
  def deep_freeze
12
- map { |k, v| v.is_a?(Hash) ? v.deep_freeze : v.freeze }.freeze
12
+ chilled = {}
13
+ each do |k, v|
14
+ chilled[k] = v.is_a?(Hash) ? v.deep_freeze : v.freeze
15
+ end
16
+
17
+ chilled.freeze
13
18
  end
14
19
 
15
20
  def deep_freeze!
16
- replace deep_freeze
21
+ replace deep_thaw.deep_freeze
22
+ end
23
+
24
+ def deep_thaw
25
+ chilled = {}
26
+ each do |k, v|
27
+ chilled[k] = v.is_a?(Hash) ? v.deep_thaw : v.dup
28
+ end
29
+
30
+ chilled.dup
31
+ end
32
+
33
+ def deep_thaw!
34
+ replace deep_thaw
17
35
  end
18
36
 
19
37
  # Turn all keys into string
@@ -30,15 +48,16 @@ module Doing
30
48
 
31
49
  # Set a nested hash value using an array
32
50
  #
33
- # @example `{}.deep_set(['one', 'two'], 'value')`
34
- # @example `=> { 'one' => { 'two' => 'value' } }
51
+ # @example
52
+ # {}.deep_set(['one', 'two'], 'value')
53
+ # # => { 'one' => { 'two' => 'value' } }
35
54
  #
36
55
  # @param path [Array] key path
37
56
  # @param value The value
38
57
  #
39
58
  def deep_set(path, value)
40
59
  if path.count == 1
41
- if value
60
+ unless value.nil? || value =~ /^ *$/
42
61
  self[path[0]] = value
43
62
  else
44
63
  delete(path[0])
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GLI
4
+ module Commands
5
+ # Help Command Monkeypatch for paginated output
6
+ class Help < Command
7
+ def show_help(global_options,options,arguments,out,error)
8
+ Doing::Pager.paginate = true
9
+
10
+ command_finder = HelpModules::CommandFinder.new(@app,arguments,error)
11
+ if options[:c]
12
+ help_output = HelpModules::HelpCompletionFormat.new(@app,command_finder,arguments).format
13
+ out.puts help_output unless help_output.nil?
14
+ elsif arguments.empty? || options[:c]
15
+ Doing::Pager.page HelpModules::GlobalHelpFormat.new(@app,@sorter,@text_wrapping_class).format
16
+ else
17
+ name = arguments.shift
18
+ command = command_finder.find_command(name)
19
+ unless command.nil?
20
+ Doing::Pager.page HelpModules::CommandHelpFormat.new(
21
+ command,
22
+ @app,
23
+ @sorter,
24
+ @synopsis_formatter_class,
25
+ @text_wrapping_class).format
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
data/lib/doing/hooks.rb CHANGED
@@ -23,7 +23,11 @@ module Doing
23
23
 
24
24
  # register hook(s) to be called later, public API
25
25
  def self.register(event, priority: DEFAULT_PRIORITY, &block)
26
- register_one(event, priority_value(priority), &block)
26
+ if event.is_a?(Array)
27
+ event.each { |ev| register_one(ev, priority_value(priority), &block) }
28
+ else
29
+ register_one(event, priority_value(priority), &block)
30
+ end
27
31
  end
28
32
 
29
33
  # Ensure the priority is a Fixnum
data/lib/doing/item.rb CHANGED
@@ -125,11 +125,11 @@ module Doing
125
125
  return true if same_time?(item_b)
126
126
 
127
127
  start_a = date
128
- interval = interval
129
- end_a = interval ? start_a + interval.to_i : start_a
128
+ a_interval = interval
129
+ end_a = a_interval ? start_a + a_interval.to_i : start_a
130
130
  start_b = item_b.date
131
- interval = item_b.interval
132
- end_b = interval ? start_b + interval.to_i : start_b
131
+ b_interval = item_b.interval
132
+ end_b = b_interval ? start_b + b_interval.to_i : start_b
133
133
  (start_a >= start_b && start_a <= end_b) || (end_a >= start_b && end_a <= end_b) || (start_a < start_b && end_a > end_b)
134
134
  end
135
135
 
@@ -216,8 +216,8 @@ module Doing
216
216
  ##
217
217
  def tags?(tags, bool = :and, negate: false)
218
218
  if bool == :pattern
219
- tags = tags.join(' ') if tags.is_a?(Array)
220
- matches = tag_pattern?(tags.gsub(/ *, */, ' '))
219
+ tags = tags.to_tags.tags_to_array.join(' ')
220
+ matches = tag_pattern?(tags)
221
221
 
222
222
  return negate ? !matches : matches
223
223
  end
@@ -283,7 +283,7 @@ module Doing
283
283
  new_title = @title.gsub(rx) { |m| yellow(m) }
284
284
  new_note.add(@note.to_s.gsub(rx) { |m| yellow(m) })
285
285
  else
286
- query = to_phrase_query(search.strip)
286
+ query = search.strip.to_phrase_query
287
287
 
288
288
  if query[:must].nil? && query[:must_not].nil?
289
289
  query[:must] = query[:should]
@@ -319,7 +319,7 @@ module Doing
319
319
  if search.is_rx? || matching == :fuzzy
320
320
  matches = @title + @note.to_s =~ search.to_rx(distance: distance, case_type: case_type)
321
321
  else
322
- query = to_phrase_query(search.strip)
322
+ query = search.strip.to_phrase_query
323
323
 
324
324
  if query[:must].nil? && query[:must_not].nil?
325
325
  query[:must] = query[:should]
@@ -612,29 +612,14 @@ module Doing
612
612
  end
613
613
  end
614
614
 
615
- def to_query(query)
616
- parser = BooleanTermParser::QueryParser.new
617
- transformer = BooleanTermParser::QueryTransformer.new
618
- parse_tree = parser.parse(query)
619
- transformer.apply(parse_tree).to_elasticsearch
620
- end
621
-
622
- def to_phrase_query(query)
623
- parser = PhraseParser::QueryParser.new
624
- transformer = PhraseParser::QueryTransformer.new
625
- parse_tree = parser.parse(query)
626
- transformer.apply(parse_tree).to_elasticsearch
627
- end
628
-
629
615
  def tag_pattern?(tags)
630
- query = to_query(tags)
616
+ query = tags.to_query
631
617
 
632
618
  no_tags?(query[:must_not]) && all_tags?(query[:must]) && any_tags?(query[:should])
633
619
  end
634
620
 
635
621
  def split_tags(tags)
636
- tags = tags.split(/ *, */) if tags.is_a? String
637
- tags.map { |t| t.strip.add_at }
622
+ tags.to_tags.tags_to_array
638
623
  end
639
624
  end
640
625
  end
data/lib/doing/items.rb CHANGED
@@ -131,7 +131,9 @@ module Doing
131
131
  out = []
132
132
  @sections.each do |section|
133
133
  out.push(section.original)
134
- in_section(section.title).each { |item| out.push(item.to_s)}
134
+ items = in_section(section.title).sort_by { |i| i.date }
135
+ items.reverse! if Doing.config.settings['doing_file_sort'].normalize_order == 'desc'
136
+ items.each { |item| out.push(item.to_s)}
135
137
  end
136
138
 
137
139
  out.join("\n")
@@ -356,7 +356,7 @@ module Doing
356
356
  next if data[:count].zero?
357
357
 
358
358
  count = data[:count]
359
- tags = data[:tag] ? data[:tag].uniq.map { |t| "@#{t}".cyan }.join(', ') : 'tags'
359
+ tags = data[:tag] ? data[:tag].uniq.map { |t| t.add_at.cyan }.join(', ') : 'tags'
360
360
  topic, m = format_counter(key, data)
361
361
  message = m.dup
362
362
  message.sub!(/%count/, count.to_s)
data/lib/doing/pager.rb CHANGED
@@ -54,8 +54,8 @@ module Doing
54
54
  read_io.close
55
55
  write_io.write(text)
56
56
  write_io.close
57
- rescue SystemCallError => e
58
- raise Errors::DoingStandardError, "Pager error, #{e}"
57
+ rescue SystemCallError # => e
58
+ # raise Errors::DoingStandardError, "Pager error, #{e}"
59
59
  end
60
60
 
61
61
  _, status = Process.waitpid2(pid)
@@ -75,7 +75,7 @@ module Doing
75
75
  note = i.note.map { |line| line.strip.link_urls(format: :markdown) } if i.note
76
76
  end
77
77
 
78
- title = "#{title} @project(#{i.section})" unless variables[:is_single]
78
+ title = "#{title} @section(#{i.section})" unless variables[:is_single]
79
79
 
80
80
  tags.concat(i.tag_array).sort!.uniq!
81
81
  flagged = day_flagged = true if i.tags?(wwid.config['marker_tag'])
@@ -48,7 +48,7 @@ module Doing
48
48
  note = i.note.map { |line| line.strip.link_urls(format: :markdown) } if i.note
49
49
  end
50
50
 
51
- title = "#{title} @project(#{i.section})" unless variables[:is_single]
51
+ title = "#{title} @section(#{i.section})" unless variables[:is_single]
52
52
 
53
53
  interval = wwid.get_interval(i, record: true) if i.title =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
54
54
  interval ||= false
@@ -49,6 +49,8 @@ module Doing
49
49
  note = []
50
50
  end
51
51
 
52
+ placeholders['tags'] = item.tags
53
+
52
54
  placeholders['date'] = item.date.strftime(opt[:format])
53
55
 
54
56
  interval = wwid.get_interval(item, record: true, formatted: false) if opt[:times]
@@ -56,8 +58,10 @@ module Doing
56
58
  interval = case opt[:interval_format].to_sym
57
59
  when :human
58
60
  interval.time_string(format: :hm)
59
- else
61
+ when :text
60
62
  interval.time_string(format: :clock)
63
+ else
64
+ interval.time_string(format: opt[:interval_format].to_sym)
61
65
  end
62
66
  end
63
67
 
@@ -69,8 +73,10 @@ module Doing
69
73
  duration = case opt[:interval_format].to_sym
70
74
  when :human
71
75
  duration.time_string(format: :hm)
72
- else
76
+ when :text
73
77
  duration.time_string(format: :clock)
78
+ else
79
+ duration.time_string(format: opt[:interval_format].to_sym)
74
80
  end
75
81
  end
76
82
  duration ||= ''
@@ -119,7 +125,7 @@ module Doing
119
125
 
120
126
  output.gsub!(/\\%/, '%')
121
127
 
122
- output.highlight_search!(opt[:search]) if opt[:search] && !opt[:not] && opt[:hilite]
128
+ output.highlight_search!(opt[:search]) if opt[:template] =~ /^temp/ && opt[:search] && !opt[:not] && opt[:hilite]
123
129
 
124
130
  out += "#{output}\n"
125
131
  end
data/lib/doing/prompt.rb CHANGED
@@ -42,7 +42,7 @@ module Doing
42
42
  end
43
43
  end
44
44
 
45
- def read_lines(prompt: 'Enter text', completions: [])
45
+ def read_lines(prompt: 'Enter text', completions: [], default_response: '')
46
46
  $stdin.reopen('/dev/tty')
47
47
  return default_response if @default_answer
48
48
 
@@ -72,8 +72,10 @@ module Doing
72
72
  res.join("\n").strip
73
73
  end
74
74
 
75
- def request_lines(prompt: 'Enter text')
75
+ def request_lines(prompt: 'Enter text', default_response: '')
76
76
  $stdin.reopen('/dev/tty')
77
+ return default_response if @default_answer
78
+
77
79
  ask_note = []
78
80
  reader = TTY::Reader.new(interrupt: -> { raise Errors::UserCancelled }, track_history: false)
79
81
  puts "#{boldgreen(prompt.sub(/:?$/, ':'))} #{yellow('Hit return for a new line, ')}#{boldwhite('enter a blank line (')}#{boldyellow('return twice')}#{boldwhite(') to end editing')}"