doing 2.1.14 → 2.1.18
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.
- checksums.yaml +4 -4
- data/.irbrc +1 -0
- data/.yardoc/checksums +14 -12
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/CHANGELOG.md +66 -0
- data/Gemfile.lock +3 -2
- data/README.md +56 -19
- data/bin/doing +134 -47
- data/docs/doc/Array.html +117 -3
- data/docs/doc/BooleanTermParser/Clause.html +1 -1
- data/docs/doc/BooleanTermParser/Operator.html +1 -1
- data/docs/doc/BooleanTermParser/Query.html +1 -1
- data/docs/doc/BooleanTermParser/QueryParser.html +1 -1
- data/docs/doc/BooleanTermParser/QueryTransformer.html +1 -1
- data/docs/doc/BooleanTermParser.html +1 -1
- data/docs/doc/Doing/Color.html +6 -2
- data/docs/doc/Doing/Completion.html +1 -1
- data/docs/doc/Doing/Configuration.html +8 -4
- data/docs/doc/Doing/Errors/DoingNoTraceError.html +1 -1
- data/docs/doc/Doing/Errors/DoingRuntimeError.html +1 -1
- data/docs/doc/Doing/Errors/DoingStandardError.html +1 -1
- data/docs/doc/Doing/Errors/EmptyInput.html +1 -1
- data/docs/doc/Doing/Errors/NoResults.html +1 -1
- data/docs/doc/Doing/Errors/PluginException.html +1 -1
- data/docs/doc/Doing/Errors/UserCancelled.html +1 -1
- data/docs/doc/Doing/Errors/WrongCommand.html +1 -1
- data/docs/doc/Doing/Errors.html +1 -1
- data/docs/doc/Doing/Hooks.html +1 -1
- data/docs/doc/Doing/Item.html +224 -2
- data/docs/doc/Doing/Items.html +2 -2
- data/docs/doc/Doing/LogAdapter.html +1 -1
- data/docs/doc/Doing/Note.html +2 -2
- data/docs/doc/Doing/Pager.html +1 -1
- data/docs/doc/Doing/Plugins.html +1 -1
- data/docs/doc/Doing/Prompt.html +69 -1
- data/docs/doc/Doing/Section.html +1 -1
- data/docs/doc/Doing/TemplateString.html +2 -2
- data/docs/doc/Doing/Util/Backup.html +1 -1
- data/docs/doc/Doing/Util.html +1 -1
- data/docs/doc/Doing/WWID.html +71 -67
- data/docs/doc/Doing.html +3 -3
- data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
- data/docs/doc/GLI/Commands.html +1 -1
- data/docs/doc/GLI.html +1 -1
- data/docs/doc/Hash.html +1 -1
- data/docs/doc/Numeric.html +279 -0
- data/docs/doc/PhraseParser/Operator.html +1 -1
- data/docs/doc/PhraseParser/PhraseClause.html +1 -1
- data/docs/doc/PhraseParser/Query.html +1 -1
- data/docs/doc/PhraseParser/QueryParser.html +1 -1
- data/docs/doc/PhraseParser/QueryTransformer.html +1 -1
- data/docs/doc/PhraseParser/TermClause.html +1 -1
- data/docs/doc/PhraseParser.html +1 -1
- data/docs/doc/Status.html +1 -1
- data/docs/doc/String.html +997 -118
- data/docs/doc/Symbol.html +1 -1
- data/docs/doc/Time.html +1 -1
- data/docs/doc/_index.html +14 -9
- data/docs/doc/class_list.html +1 -1
- data/docs/doc/file.README.html +41 -15
- data/docs/doc/index.html +41 -15
- data/docs/doc/method_list.html +448 -312
- data/docs/doc/top-level-namespace.html +2 -2
- data/docs/index.md +56 -19
- data/doing.gemspec +1 -0
- data/doing.rdoc +36 -6
- data/example_plugin.rb +2 -4
- data/lib/completion/_doing.zsh +8 -8
- data/lib/completion/doing.bash +12 -12
- data/lib/completion/doing.fish +8 -3
- data/lib/doing/array_chronify.rb +57 -0
- data/lib/doing/colors.rb +4 -0
- data/lib/doing/configuration.rb +6 -2
- data/lib/doing/item.rb +83 -0
- data/lib/doing/log_adapter.rb +3 -3
- data/lib/doing/numeric_chronify.rb +40 -0
- data/lib/doing/plugins/export/dayone_export.rb +1 -1
- data/lib/doing/plugins/export/json_export.rb +2 -2
- data/lib/doing/plugins/export/template_export.rb +49 -90
- data/lib/doing/prompt.rb +52 -0
- data/lib/doing/string.rb +137 -33
- data/lib/doing/string_chronify.rb +112 -14
- data/lib/doing/template_string.rb +1 -1
- data/lib/doing/time.rb +4 -4
- data/lib/doing/util_backup.rb +1 -1
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +107 -101
- data/lib/doing.rb +35 -31
- data/lib/examples/plugins/say_export.rb +1 -4
- metadata +26 -2
data/lib/doing/wwid.rb
CHANGED
@@ -185,34 +185,11 @@ module Doing
|
|
185
185
|
|
186
186
|
date = nil
|
187
187
|
iso_rx = /\d{4}-\d\d-\d\d \d\d:\d\d/
|
188
|
-
watch_tags = [
|
189
|
-
'start(?:ed)?',
|
190
|
-
'beg[ia]n',
|
191
|
-
'done',
|
192
|
-
'finished',
|
193
|
-
'completed?',
|
194
|
-
'waiting',
|
195
|
-
'defer(?:red)?'
|
196
|
-
]
|
197
|
-
if @config['date_tags']
|
198
|
-
date_tags = @config['date_tags']
|
199
|
-
date_tags = date_tags.split(/ *, */) if date_tags.is_a?(String)
|
200
|
-
date_tags.map! do |tag|
|
201
|
-
tag.sub(/^@/, '').gsub(/\((?!\?:)(.*?)\)/, '(?:\1)').strip
|
202
|
-
end
|
203
|
-
watch_tags.concat(date_tags).uniq!
|
204
|
-
end
|
205
|
-
|
206
|
-
done_rx = /(?<=^| )@(?<tag>#{watch_tags.join('|')})\((?<date>.*?)\)/i
|
207
188
|
date_rx = /^(?:\s*- )?(?<date>.*?) \| (?=\S)/
|
208
189
|
|
209
|
-
title.
|
210
|
-
|
211
|
-
|
212
|
-
d = m['date']
|
213
|
-
parsed_date = d =~ date_rx ? Time.parse(d) : d.chronify(guess: :begin)
|
214
|
-
parsed_date.nil? ? m[0] : "@#{t}(#{parsed_date.strftime('%F %R')})"
|
215
|
-
end
|
190
|
+
raise EmptyInput, 'No content' if title.sub(/^.*?\| */, '').strip.empty?
|
191
|
+
|
192
|
+
title.expand_date_tags(@config['date_tags'])
|
216
193
|
|
217
194
|
if title =~ date_rx
|
218
195
|
m = title.match(date_rx)
|
@@ -369,7 +346,8 @@ module Doing
|
|
369
346
|
items.each_with_index do |i, x|
|
370
347
|
next if i.title =~ / @done/
|
371
348
|
|
372
|
-
|
349
|
+
finish_date = verify_duration(i.date, opt[:back], title: i.title)
|
350
|
+
items[x].tag('done', value: finish_date.strftime('%F %R'))
|
373
351
|
break
|
374
352
|
end
|
375
353
|
end
|
@@ -820,17 +798,18 @@ module Doing
|
|
820
798
|
end
|
821
799
|
|
822
800
|
def delete_items(items, force: false)
|
823
|
-
|
824
|
-
if
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
801
|
+
items.slice(0, 5).each { |i| puts i.to_pretty } unless force
|
802
|
+
puts softpurple("+ #{items.size - 5} additional #{'item'.to_p(items.size - 5)}") if items.size > 5 && !force
|
803
|
+
|
804
|
+
res = force ? true : Prompt.yn("Delete #{items.size} #{'item'.to_p(items.size)}?", default_response: 'y')
|
805
|
+
return unless res
|
806
|
+
|
807
|
+
items.each { |i| Hooks.trigger :post_entry_removed, self, @content.delete_item(i, single: items.count == 1) }
|
808
|
+
write(@doing_file)
|
831
809
|
end
|
832
810
|
|
833
811
|
def edit_items(items)
|
812
|
+
items.sort_by! { |i| i.date }
|
834
813
|
editable_items = []
|
835
814
|
|
836
815
|
items.each do |i|
|
@@ -839,16 +818,16 @@ module Doing
|
|
839
818
|
editable += "\n#{old_note}" unless old_note.nil?
|
840
819
|
editable_items << editable
|
841
820
|
end
|
842
|
-
divider = "
|
821
|
+
divider = "-----------"
|
843
822
|
notice =<<~EONOTICE
|
844
823
|
# - You may delete entries, but leave all divider lines (---) in place.
|
845
824
|
# - Start and @done dates replaced with a time string (yesterday 3pm) will
|
846
825
|
# be parsed automatically. Do not delete the pipe (|) between start date
|
847
826
|
# and entry title.
|
848
827
|
EONOTICE
|
849
|
-
input = "#{editable_items.map(&:strip).join(divider)}\n\n#{notice}"
|
828
|
+
input = "#{editable_items.map(&:strip).join("\n#{divider}\n")}\n\n#{notice}"
|
850
829
|
|
851
|
-
new_items = fork_editor(input).split(
|
830
|
+
new_items = fork_editor(input).split(/^#{divider}/).map(&:strip)
|
852
831
|
|
853
832
|
new_items.each_with_index do |new_item, i|
|
854
833
|
input_lines = new_item.split(/[\n\r]+/).delete_if(&:ignore?)
|
@@ -857,7 +836,7 @@ module Doing
|
|
857
836
|
if first_line.nil? || first_line =~ /^#{divider.strip}$/ || first_line.strip.empty?
|
858
837
|
deleted = @content.delete_item(items[i], single: new_items.count == 1)
|
859
838
|
Hooks.trigger :post_entry_removed, self, deleted
|
860
|
-
Doing.logger.
|
839
|
+
Doing.logger.info('Deleted:', deleted.title)
|
861
840
|
else
|
862
841
|
date, title, note = format_input(new_item)
|
863
842
|
|
@@ -985,8 +964,14 @@ module Doing
|
|
985
964
|
type = action =~ /^add/ ? 'add' : 'remove'
|
986
965
|
raise InvalidArgument, "'add tag' and 'remove tag' can not be used together" if opt[:tag]
|
987
966
|
|
988
|
-
|
989
|
-
|
967
|
+
tags = type == 'add' ? all_tags(@content) : all_tags(items)
|
968
|
+
|
969
|
+
puts "#{yellow}Separate multiple tags with spaces, hit tab to complete known tags#{type == 'add' ? ', include values with tag(value)' : ''}"
|
970
|
+
puts "#{boldgreen}Available tags: #{boldwhite}#{tags.sort.map(&:add_at).join(', ')}" if type == 'remove'
|
971
|
+
tag = Prompt.read_line(prompt: "Tags to #{type}", completions: tags)
|
972
|
+
|
973
|
+
# print "#{yellow("Tag to #{type}: ")}#{reset}"
|
974
|
+
# tag = $stdin.gets
|
990
975
|
next if tag =~ /^ *$/
|
991
976
|
|
992
977
|
opt[:tag] = tag.strip.sub(/^@/, '')
|
@@ -1001,15 +986,16 @@ module Doing
|
|
1001
986
|
'--no-sort',
|
1002
987
|
'--info=hidden'
|
1003
988
|
])
|
1004
|
-
next if
|
989
|
+
next if output_format =~ /^ *$/
|
1005
990
|
|
1006
991
|
raise UserCancelled unless output_format
|
1007
992
|
|
1008
993
|
opt[:output] = output_format.strip
|
1009
994
|
res = opt[:force] ? false : Prompt.yn('Save to file?', default_response: 'n')
|
1010
995
|
if res
|
1011
|
-
print "#{yellow('File path/name: ')}#{reset}"
|
1012
|
-
filename = $stdin.gets.strip
|
996
|
+
# print "#{yellow('File path/name: ')}#{reset}"
|
997
|
+
# filename = $stdin.gets.strip
|
998
|
+
filename = Prompt.read_line(prompt: 'File path/name')
|
1013
999
|
next if filename.empty?
|
1014
1000
|
|
1015
1001
|
opt[:save_to] = filename
|
@@ -1089,6 +1075,7 @@ module Doing
|
|
1089
1075
|
tag = opt[:tag]
|
1090
1076
|
items.map! do |i|
|
1091
1077
|
i.tag(tag, date: false, remove: opt[:remove], single: single)
|
1078
|
+
i.expand_date_tags(@config['date_tags'])
|
1092
1079
|
Hooks.trigger :post_entry_updated, self, i
|
1093
1080
|
end
|
1094
1081
|
end
|
@@ -1116,10 +1103,10 @@ module Doing
|
|
1116
1103
|
i
|
1117
1104
|
end
|
1118
1105
|
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
options = { section: '
|
1106
|
+
export_items = Items.new
|
1107
|
+
export_items.concat(items)
|
1108
|
+
export_items.add_section(Section.new('Export'), log: false)
|
1109
|
+
options = { section: 'All' }
|
1123
1110
|
|
1124
1111
|
if opt[:output] =~ /doing/
|
1125
1112
|
options[:output] = 'template'
|
@@ -1129,7 +1116,7 @@ module Doing
|
|
1129
1116
|
options[:template] = opt[:template] || nil
|
1130
1117
|
end
|
1131
1118
|
|
1132
|
-
output = list_section(options) # hooked
|
1119
|
+
output = list_section(options, items: export_items) # hooked
|
1133
1120
|
|
1134
1121
|
if opt[:save_to]
|
1135
1122
|
file = File.expand_path(opt[:save_to])
|
@@ -1148,6 +1135,26 @@ module Doing
|
|
1148
1135
|
end
|
1149
1136
|
end
|
1150
1137
|
|
1138
|
+
def verify_duration(date, finish_date, title: nil)
|
1139
|
+
max_elapsed = @config.dig('interaction', 'confirm_longer_than') || 0
|
1140
|
+
max_elapsed = max_elapsed.chronify_qty if max_elapsed.is_a?(String)
|
1141
|
+
elapsed = finish_date - date
|
1142
|
+
|
1143
|
+
if max_elapsed.positive? && (elapsed > max_elapsed)
|
1144
|
+
puts boldwhite(title) if title
|
1145
|
+
human = elapsed.time_string(format: :natural)
|
1146
|
+
res = Prompt.yn(yellow("Did this entry actually take #{human}"), default_response: true)
|
1147
|
+
unless res
|
1148
|
+
new_elapsed = Prompt.enter_text('How long did it take?').chronify_qty
|
1149
|
+
raise InvalidTimeExpression, 'Unrecognized time span entry' unless new_elapsed.positive?
|
1150
|
+
|
1151
|
+
finish_date = date + new_elapsed if new_elapsed
|
1152
|
+
end
|
1153
|
+
end
|
1154
|
+
|
1155
|
+
finish_date
|
1156
|
+
end
|
1157
|
+
|
1151
1158
|
##
|
1152
1159
|
## Tag the last entry or X entries
|
1153
1160
|
##
|
@@ -1186,6 +1193,19 @@ module Doing
|
|
1186
1193
|
|
1187
1194
|
raise NoResults, 'no items matched your search' if items.empty?
|
1188
1195
|
|
1196
|
+
if opt[:tags].empty? && !opt[:autotag]
|
1197
|
+
completions = opt[:remove] ? all_tags(items) : all_tags(@content)
|
1198
|
+
if opt[:remove]
|
1199
|
+
puts "#{yellow}Available tags: #{boldwhite}#{completions.map(&:add_at).join(', ')}"
|
1200
|
+
else
|
1201
|
+
puts "#{yellow}Use tab to complete known tags"
|
1202
|
+
end
|
1203
|
+
opt[:tags] = Doing::Prompt.read_line(prompt: "Enter tag(s) to #{opt[:remove] ? 'remove' : 'add'}",
|
1204
|
+
completions: completions,
|
1205
|
+
default_response: '').to_tags
|
1206
|
+
raise UserCancelled, 'No tags provided' if opt[:tags].empty?
|
1207
|
+
end
|
1208
|
+
|
1189
1209
|
items.each do |item|
|
1190
1210
|
added = []
|
1191
1211
|
removed = []
|
@@ -1209,21 +1229,8 @@ module Doing
|
|
1209
1229
|
else
|
1210
1230
|
next_entry.date - 60
|
1211
1231
|
end
|
1212
|
-
elsif opt[:took]
|
1213
|
-
if item.date + opt[:took] > Time.now
|
1214
|
-
item.date = Time.now - opt[:took]
|
1215
|
-
done_date = Time.now
|
1216
|
-
else
|
1217
|
-
done_date = item.date + opt[:took]
|
1218
|
-
end
|
1219
|
-
elsif opt[:back]
|
1220
|
-
done_date = if opt[:back].is_a? Integer
|
1221
|
-
item.date + opt[:back]
|
1222
|
-
else
|
1223
|
-
item.date + (opt[:back] - item.date)
|
1224
|
-
end
|
1225
1232
|
else
|
1226
|
-
done_date =
|
1233
|
+
done_date = item.calculate_end_date(opt)
|
1227
1234
|
end
|
1228
1235
|
|
1229
1236
|
opt[:tags].each do |tag|
|
@@ -1234,7 +1241,28 @@ module Doing
|
|
1234
1241
|
next
|
1235
1242
|
end
|
1236
1243
|
|
1244
|
+
|
1237
1245
|
tag = tag.strip
|
1246
|
+
|
1247
|
+
if tag =~ /^done$/
|
1248
|
+
max_elapsed = @config.dig('interaction', 'confirm_longer_than') || 0
|
1249
|
+
max_elapsed = max_elapsed.chronify_qty if max_elapsed.is_a?(String)
|
1250
|
+
elapsed = done_date - item.date
|
1251
|
+
|
1252
|
+
if max_elapsed.positive? && (elapsed > max_elapsed) && !opt[:took]
|
1253
|
+
puts boldwhite(item.title)
|
1254
|
+
human = elapsed.time_string(format: :natural)
|
1255
|
+
res = Prompt.yn(yellow("Did this actually take #{human}"), default_response: true)
|
1256
|
+
unless res
|
1257
|
+
new_elapsed = Prompt.enter_text('How long did it take?').chronify_qty
|
1258
|
+
raise InvalidTimeExpression, 'Unrecognized time span entry' unless new_elapsed > 0
|
1259
|
+
|
1260
|
+
opt[:took] = new_elapsed
|
1261
|
+
done_date = item.calculate_end_date(opt) if opt[:took]
|
1262
|
+
end
|
1263
|
+
end
|
1264
|
+
end
|
1265
|
+
|
1238
1266
|
if opt[:remove] || opt[:rename] || opt[:value]
|
1239
1267
|
rename_to = nil
|
1240
1268
|
if opt[:value]
|
@@ -1272,6 +1300,7 @@ module Doing
|
|
1272
1300
|
logger.warn('Skipped:', 'Archiving is skipped when operating on all entries')
|
1273
1301
|
end
|
1274
1302
|
|
1303
|
+
item.expand_date_tags(@config['date_tags'])
|
1275
1304
|
Hooks.trigger :post_entry_updated, self, item
|
1276
1305
|
end
|
1277
1306
|
|
@@ -1621,6 +1650,7 @@ module Doing
|
|
1621
1650
|
|
1622
1651
|
opt[:output] ||= 'template'
|
1623
1652
|
opt[:wrap_width] ||= @config['templates']['default']['wrap_width'] || 0
|
1653
|
+
|
1624
1654
|
output(items, title, is_single, opt)
|
1625
1655
|
end
|
1626
1656
|
|
@@ -2005,7 +2035,7 @@ module Doing
|
|
2005
2035
|
EOS
|
2006
2036
|
sorted_tags_data.reverse.each do |k, v|
|
2007
2037
|
if v > 0
|
2008
|
-
output += "<tr><td style='text-align:left;'>#{k}</td><td style='text-align:left;'>#{
|
2038
|
+
output += "<tr><td style='text-align:left;'>#{k}</td><td style='text-align:left;'>#{v.time_string(format: :clock)}</td></tr>\n"
|
2009
2039
|
end
|
2010
2040
|
end
|
2011
2041
|
tail = <<EOS
|
@@ -2016,7 +2046,7 @@ EOS
|
|
2016
2046
|
<tfoot>
|
2017
2047
|
<tr>
|
2018
2048
|
<td style="text-align:left;"><strong>Total</strong></td>
|
2019
|
-
<td style="text-align:left;">#{
|
2049
|
+
<td style="text-align:left;">#{total.time_string(format: :clock)}</td>
|
2020
2050
|
</tr>
|
2021
2051
|
</tfoot>
|
2022
2052
|
</table>
|
@@ -2031,7 +2061,7 @@ EOS
|
|
2031
2061
|
EOS
|
2032
2062
|
sorted_tags_data.reverse.each do |k, v|
|
2033
2063
|
if v > 0
|
2034
|
-
output += "| #{' ' * (pad - k.length)}#{k} | #{
|
2064
|
+
output += "| #{' ' * (pad - k.length)}#{k} | #{v.time_string(format: :clock)} |\n"
|
2035
2065
|
end
|
2036
2066
|
end
|
2037
2067
|
tail = "[Tag Totals]"
|
@@ -2039,11 +2069,10 @@ EOS
|
|
2039
2069
|
when :json
|
2040
2070
|
output = []
|
2041
2071
|
sorted_tags_data.reverse.each do |k, v|
|
2042
|
-
d, h, m = format_time(v)
|
2043
2072
|
output << {
|
2044
2073
|
'tag' => k,
|
2045
2074
|
'seconds' => v,
|
2046
|
-
'formatted' => format
|
2075
|
+
'formatted' => v.time_string(format: :clock)
|
2047
2076
|
}
|
2048
2077
|
end
|
2049
2078
|
output
|
@@ -2054,8 +2083,7 @@ EOS
|
|
2054
2083
|
(max - k.length).times do
|
2055
2084
|
spacer += ' '
|
2056
2085
|
end
|
2057
|
-
|
2058
|
-
output.push("┃ #{spacer}#{k}:#{format('%<h> 4dh %<m>02dm', h: h, m: m)} ┃")
|
2086
|
+
output.push("┃ #{spacer}#{k}:#{v.time_string(format: :hm)} ┃")
|
2059
2087
|
end
|
2060
2088
|
|
2061
2089
|
header = '┏━━ Tag Totals '
|
@@ -2068,14 +2096,14 @@ EOS
|
|
2068
2096
|
(max + 12).times { divider += '━' }
|
2069
2097
|
divider += '┫'
|
2070
2098
|
output = output.empty? ? '' : "\n#{header}\n#{output.join("\n")}"
|
2071
|
-
d, h, m = format_time(total, human: true)
|
2072
2099
|
output += "\n#{divider}"
|
2073
2100
|
spacer = ''
|
2074
2101
|
(max - 6).times do
|
2075
2102
|
spacer += ' '
|
2076
2103
|
end
|
2104
|
+
total_time = total.time_string(format: :hm)
|
2077
2105
|
total = "┃ #{spacer}total: "
|
2078
|
-
total +=
|
2106
|
+
total += total_time
|
2079
2107
|
total += ' ┃'
|
2080
2108
|
output += "\n#{total}"
|
2081
2109
|
output += "\n#{footer}"
|
@@ -2087,13 +2115,11 @@ EOS
|
|
2087
2115
|
(max - k.length).times do
|
2088
2116
|
spacer += ' '
|
2089
2117
|
end
|
2090
|
-
|
2091
|
-
output.push("#{k}:#{spacer}#{format('%<d>02d:%<h>02d:%<m>02d', d: d, h: h, m: m)}")
|
2118
|
+
output.push("#{k}:#{spacer}#{v.time_string(format: :clock)}")
|
2092
2119
|
end
|
2093
2120
|
|
2094
2121
|
output = output.empty? ? '' : "\n--- Tag Totals ---\n#{output.join("\n")}"
|
2095
|
-
|
2096
|
-
output += "\n\nTotal tracked: #{format('%<d>02d:%<h>02d:%<m>02d', d: d, h: h, m: m)}\n"
|
2122
|
+
output += "\n\nTotal tracked: #{total.time_string(format: :clock)}\n"
|
2097
2123
|
output
|
2098
2124
|
end
|
2099
2125
|
end
|
@@ -2118,39 +2144,19 @@ EOS
|
|
2118
2144
|
record_tag_times(item, seconds) if record
|
2119
2145
|
return seconds.positive? ? seconds : false unless formatted
|
2120
2146
|
|
2121
|
-
return seconds.positive? ? format
|
2147
|
+
return seconds.positive? ? seconds.time_string(format: :clock) : false
|
2122
2148
|
end
|
2123
2149
|
|
2124
2150
|
false
|
2125
2151
|
end
|
2126
2152
|
|
2127
2153
|
##
|
2128
|
-
##
|
2154
|
+
## Load configuration files and updated the @config
|
2155
|
+
## attribute with a Doing::Configuration object
|
2129
2156
|
##
|
2130
|
-
## @param
|
2157
|
+
## @param filename [String] (optional) path to
|
2158
|
+
## alternative config file
|
2131
2159
|
##
|
2132
|
-
def format_time(seconds, human: false)
|
2133
|
-
return [0, 0, 0] if seconds.nil?
|
2134
|
-
|
2135
|
-
if seconds.instance_of?(String) && seconds =~ /(\d+):(\d+):(\d+)/
|
2136
|
-
h = Regexp.last_match(1)
|
2137
|
-
m = Regexp.last_match(2)
|
2138
|
-
s = Regexp.last_match(3)
|
2139
|
-
seconds = (h.to_i * 60 * 60) + (m.to_i * 60) + s.to_i
|
2140
|
-
end
|
2141
|
-
minutes = (seconds / 60).to_i
|
2142
|
-
hours = (minutes / 60).to_i
|
2143
|
-
if human
|
2144
|
-
minutes = (minutes % 60).to_i
|
2145
|
-
[0, hours, minutes]
|
2146
|
-
else
|
2147
|
-
days = (hours / 24).to_i
|
2148
|
-
hours = (hours % 24).to_i
|
2149
|
-
minutes = (minutes % 60).to_i
|
2150
|
-
[days, hours, minutes]
|
2151
|
-
end
|
2152
|
-
end
|
2153
|
-
|
2154
2160
|
def configure(filename = nil)
|
2155
2161
|
if filename
|
2156
2162
|
Doing.config_with(filename, { ignore_local: true })
|
data/lib/doing.rb
CHANGED
@@ -9,43 +9,47 @@ require 'csv'
|
|
9
9
|
require 'tempfile'
|
10
10
|
require 'zlib'
|
11
11
|
require 'base64'
|
12
|
+
require 'plist'
|
13
|
+
require 'readline'
|
14
|
+
require 'haml'
|
15
|
+
require 'json'
|
16
|
+
require 'logger'
|
17
|
+
require 'safe_yaml/load'
|
12
18
|
|
13
19
|
require 'chronic'
|
14
20
|
require 'tty-link'
|
15
21
|
require 'tty-which'
|
16
22
|
require 'tty-markdown'
|
17
23
|
require 'tty-reader'
|
18
|
-
require '
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
require 'doing/boolean_term_parser'
|
48
|
-
require 'doing/phrase_parser'
|
24
|
+
require 'tty-screen'
|
25
|
+
|
26
|
+
require_relative 'doing/hash'
|
27
|
+
require_relative 'doing/colors'
|
28
|
+
require_relative 'doing/template_string'
|
29
|
+
require_relative 'doing/string'
|
30
|
+
require_relative 'doing/time'
|
31
|
+
require_relative 'doing/array'
|
32
|
+
require_relative 'doing/symbol'
|
33
|
+
require_relative 'doing/util'
|
34
|
+
require_relative 'doing/util_backup'
|
35
|
+
require_relative 'doing/configuration'
|
36
|
+
require_relative 'doing/section'
|
37
|
+
require_relative 'doing/items'
|
38
|
+
require_relative 'doing/note'
|
39
|
+
require_relative 'doing/item'
|
40
|
+
require_relative 'doing/wwid'
|
41
|
+
require_relative 'doing/log_adapter'
|
42
|
+
require_relative 'doing/prompt'
|
43
|
+
require_relative 'doing/errors'
|
44
|
+
require_relative 'doing/hooks'
|
45
|
+
require_relative 'doing/plugin_manager'
|
46
|
+
require_relative 'doing/pager'
|
47
|
+
require_relative 'doing/completion'
|
48
|
+
require_relative 'doing/boolean_term_parser'
|
49
|
+
require_relative 'doing/phrase_parser'
|
50
|
+
require_relative 'doing/array_chronify'
|
51
|
+
require_relative 'doing/numeric_chronify'
|
52
|
+
require_relative 'doing/string_chronify'
|
49
53
|
# require 'doing/markdown_document_listener'
|
50
54
|
|
51
55
|
# Main doing module
|
@@ -149,11 +149,8 @@ module Doing
|
|
149
149
|
finished_at = i.end_date
|
150
150
|
took += finished_at.strftime('%A %B %e at %I:%M%p')
|
151
151
|
|
152
|
-
d, h, m = wwid.format_time(interval)
|
153
152
|
took += ' and it took'
|
154
|
-
took +=
|
155
|
-
took += " #{h.to_i} hours" if h.to_i.positive?
|
156
|
-
took += " #{m.to_i} minutes" if m.to_i.positive?
|
153
|
+
took += interval.time_string(format: :natural)
|
157
154
|
end
|
158
155
|
end
|
159
156
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: doing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.
|
4
|
+
version: 2.1.18
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brett Terpstra
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-01-
|
11
|
+
date: 2022-01-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: safe_yaml
|
@@ -366,6 +366,26 @@ dependencies:
|
|
366
366
|
- - ">="
|
367
367
|
- !ruby/object:Gem::Version
|
368
368
|
version: 0.9.0
|
369
|
+
- !ruby/object:Gem::Dependency
|
370
|
+
name: tty-screen
|
371
|
+
requirement: !ruby/object:Gem::Requirement
|
372
|
+
requirements:
|
373
|
+
- - "~>"
|
374
|
+
- !ruby/object:Gem::Version
|
375
|
+
version: '0.8'
|
376
|
+
- - ">="
|
377
|
+
- !ruby/object:Gem::Version
|
378
|
+
version: 0.8.1
|
379
|
+
type: :runtime
|
380
|
+
prerelease: false
|
381
|
+
version_requirements: !ruby/object:Gem::Requirement
|
382
|
+
requirements:
|
383
|
+
- - "~>"
|
384
|
+
- !ruby/object:Gem::Version
|
385
|
+
version: '0.8'
|
386
|
+
- - ">="
|
387
|
+
- !ruby/object:Gem::Version
|
388
|
+
version: 0.8.1
|
369
389
|
- !ruby/object:Gem::Dependency
|
370
390
|
name: parslet
|
371
391
|
requirement: !ruby/object:Gem::Requirement
|
@@ -416,6 +436,7 @@ extensions: []
|
|
416
436
|
extra_rdoc_files:
|
417
437
|
- README.md
|
418
438
|
files:
|
439
|
+
- ".irbrc"
|
419
440
|
- ".yardoc/checksums"
|
420
441
|
- ".yardoc/complete"
|
421
442
|
- ".yardoc/object_types"
|
@@ -477,6 +498,7 @@ files:
|
|
477
498
|
- docs/doc/GLI/Commands.html
|
478
499
|
- docs/doc/GLI/Commands/MarkdownDocumentListener.html
|
479
500
|
- docs/doc/Hash.html
|
501
|
+
- docs/doc/Numeric.html
|
480
502
|
- docs/doc/PhraseParser.html
|
481
503
|
- docs/doc/PhraseParser/Operator.html
|
482
504
|
- docs/doc/PhraseParser/PhraseClause.html
|
@@ -515,6 +537,7 @@ files:
|
|
515
537
|
- lib/completion/doing.fish
|
516
538
|
- lib/doing.rb
|
517
539
|
- lib/doing/array.rb
|
540
|
+
- lib/doing/array_chronify.rb
|
518
541
|
- lib/doing/boolean_term_parser.rb
|
519
542
|
- lib/doing/cli_status.rb
|
520
543
|
- lib/doing/colors.rb
|
@@ -532,6 +555,7 @@ files:
|
|
532
555
|
- lib/doing/log_adapter.rb
|
533
556
|
- lib/doing/markdown_document_listener.rb
|
534
557
|
- lib/doing/note.rb
|
558
|
+
- lib/doing/numeric_chronify.rb
|
535
559
|
- lib/doing/pager.rb
|
536
560
|
- lib/doing/phrase_parser.rb
|
537
561
|
- lib/doing/plugin_manager.rb
|