doing 2.1.37 → 2.1.40
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/CHANGELOG.md +61 -0
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/Rakefile +7 -1
- data/bin/commands/config.rb +43 -34
- data/bin/commands/done.rb +1 -18
- data/bin/commands/finish.rb +30 -25
- data/bin/commands/grep.rb +3 -14
- data/bin/commands/last.rb +2 -8
- data/bin/commands/meanwhile.rb +13 -6
- data/bin/commands/now.rb +2 -4
- data/bin/commands/on.rb +4 -15
- data/bin/commands/recent.rb +2 -8
- data/bin/commands/reset.rb +24 -1
- data/bin/commands/select.rb +1 -1
- data/bin/commands/show.rb +8 -16
- data/bin/commands/since.rb +1 -12
- data/bin/commands/today.rb +2 -13
- data/bin/commands/view.rb +1 -1
- data/bin/commands/yesterday.rb +2 -13
- data/bin/doing +41 -36
- data/docs/doc/Array.html +1 -1
- 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 +166 -20
- data/docs/doc/Doing/Completion.html +1 -1
- data/docs/doc/Doing/Configuration.html +1 -1
- data/docs/doc/Doing/Errors/DoingNoTraceError.html +7 -3
- data/docs/doc/Doing/Errors/DoingRuntimeError.html +7 -3
- data/docs/doc/Doing/Errors/DoingStandardError.html +1 -1
- data/docs/doc/Doing/Errors/EmptyInput.html +10 -2
- data/docs/doc/Doing/Errors/HistoryLimitError.html +194 -0
- data/docs/doc/Doing/Errors/InvalidPlugin.html +194 -0
- data/docs/doc/Doing/Errors/MissingBackupFile.html +194 -0
- data/docs/doc/Doing/Errors/NoResults.html +10 -2
- data/docs/doc/Doing/Errors/PluginException.html +1 -1
- data/docs/doc/Doing/Errors/UserCancelled.html +10 -2
- data/docs/doc/Doing/Errors/WrongCommand.html +10 -2
- data/docs/doc/Doing/Errors.html +9 -9
- data/docs/doc/Doing/Hooks.html +1 -1
- data/docs/doc/Doing/Item.html +114 -1576
- data/docs/doc/Doing/Items.html +121 -5
- data/docs/doc/Doing/Logger.html +1 -1
- data/docs/doc/Doing/Note.html +1 -1
- data/docs/doc/Doing/Pager.html +1 -1
- data/docs/doc/Doing/Plugins.html +1 -1
- data/docs/doc/Doing/Prompt.html +2 -2
- data/docs/doc/Doing/Section.html +1 -1
- data/docs/doc/Doing/TemplateString.html +2 -2
- data/docs/doc/Doing/Types.html +1 -1
- data/docs/doc/Doing/Util/Backup.html +5 -5
- data/docs/doc/Doing/Util.html +1 -1
- data/docs/doc/Doing/WWID.html +197 -4033
- data/docs/doc/Doing.html +2 -2
- data/docs/doc/FalseClass.html +1 -1
- data/docs/doc/GLI/Commands/Help.html +1 -1
- 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/Object.html +1 -1
- 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 +1 -1
- data/docs/doc/Symbol.html +1 -1
- data/docs/doc/Time.html +1 -1
- data/docs/doc/TrueClass.html +1 -1
- data/docs/doc/_index.html +26 -5
- data/docs/doc/class_list.html +1 -1
- data/docs/doc/file.README.html +2 -2
- data/docs/doc/index.html +2 -2
- data/docs/doc/method_list.html +237 -709
- data/docs/doc/top-level-namespace.html +3 -3
- data/docs/index.md +1 -1
- data/doing.rdoc +54 -7
- data/lib/completion/_doing.zsh +6 -6
- data/lib/completion/doing.bash +10 -10
- data/lib/completion/doing.fish +8 -2
- data/lib/doing/add_options.rb +31 -1
- data/lib/doing/chronify/array.rb +68 -18
- data/lib/doing/chronify/string.rb +3 -1
- data/lib/doing/colors.rb +77 -30
- data/lib/doing/completion.rb +4 -5
- data/lib/doing/errors.rb +51 -35
- data/lib/doing/hooks.rb +3 -3
- data/lib/doing/item/dates.rb +112 -0
- data/lib/doing/item/query.rb +433 -0
- data/lib/doing/item/state.rb +59 -0
- data/lib/doing/item/tags.rb +87 -0
- data/lib/doing/item.rb +6 -537
- data/lib/doing/items.rb +39 -14
- data/lib/doing/plugin_manager.rb +3 -3
- data/lib/doing/plugins/export/template_export.rb +4 -4
- data/lib/doing/plugins/import/cal_to_json.scpt +0 -0
- data/lib/doing/prompt.rb +6 -8
- data/lib/doing/string/tags.rb +8 -2
- data/lib/doing/util_backup.rb +6 -8
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid/display.rb +399 -0
- data/lib/doing/wwid/editor.rb +214 -0
- data/lib/doing/wwid/filetools.rb +186 -0
- data/lib/doing/wwid/filter.rb +218 -0
- data/lib/doing/wwid/guess.rb +87 -0
- data/lib/doing/wwid/interactive.rb +385 -0
- data/lib/doing/wwid/modify.rb +618 -0
- data/lib/doing/wwid/tags.rb +54 -0
- data/lib/doing/wwid/timers.rb +345 -0
- data/lib/doing/wwid/wwidutil.rb +104 -0
- data/lib/doing/wwid.rb +31 -2308
- metadata +19 -2
data/lib/doing/prompt.rb
CHANGED
|
@@ -58,14 +58,12 @@ module Doing
|
|
|
58
58
|
comp = proc { |s| completions.grep(/^#{Regexp.escape(s)}/) }
|
|
59
59
|
Readline.completion_append_character = ' '
|
|
60
60
|
Readline.completion_proc = comp
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
prompt_text << yellow(' to cancel')
|
|
68
|
-
puts prompt_text.join('')
|
|
61
|
+
puts format(['%<promptcolor>s%<prompt>s %<textcolor>sEnter a blank line',
|
|
62
|
+
'(%<keycolor>sreturn twice%<textcolor>s)',
|
|
63
|
+
'to end editing and save,',
|
|
64
|
+
'%<keycolor>sCTRL-C%<textcolor>s to cancel%<reset>s'].join(' '),
|
|
65
|
+
{ promptcolor: boldgreen, prompt: prompt.sub(/:?$/, ':'),
|
|
66
|
+
textcolor: yellow, keycolor: boldwhite, reset: reset })
|
|
69
67
|
|
|
70
68
|
res = []
|
|
71
69
|
|
data/lib/doing/string/tags.rb
CHANGED
|
@@ -117,14 +117,20 @@ module Doing
|
|
|
117
117
|
else
|
|
118
118
|
Doing.logger.debug('Skipped:', "not tagged #{"@#{tag}".cyan}")
|
|
119
119
|
end
|
|
120
|
-
elsif title =~ /@#{tag}(?=[ (]|$)/
|
|
120
|
+
elsif title =~ /@#{tag}(?=[ (]|$)/ && !value.good?
|
|
121
121
|
Doing.logger.debug('Skipped:', "already tagged #{"@#{tag}".cyan}")
|
|
122
122
|
return title
|
|
123
123
|
else
|
|
124
124
|
add = tag
|
|
125
125
|
add += "(#{value})" unless value.nil?
|
|
126
|
+
|
|
126
127
|
title.chomp!
|
|
127
|
-
|
|
128
|
+
|
|
129
|
+
if value && title =~ /@#{tag}(?=[ (]|$)/
|
|
130
|
+
title.sub!(/@#{tag}(\(.*?\))?/, "@#{add}")
|
|
131
|
+
else
|
|
132
|
+
title += " @#{add}"
|
|
133
|
+
end
|
|
128
134
|
|
|
129
135
|
title.dedup_tags!
|
|
130
136
|
title.chomp!
|
data/lib/doing/util_backup.rb
CHANGED
|
@@ -62,7 +62,7 @@ module Doing
|
|
|
62
62
|
filename ||= Doing.setting('doing_file')
|
|
63
63
|
|
|
64
64
|
backup_file = last_backup(filename, count: count)
|
|
65
|
-
raise
|
|
65
|
+
raise HistoryLimitError, 'End of undo history' if backup_file.nil?
|
|
66
66
|
|
|
67
67
|
save_undone(filename)
|
|
68
68
|
FileUtils.mv(backup_file, filename)
|
|
@@ -86,7 +86,7 @@ module Doing
|
|
|
86
86
|
skipped = undones.slice!(0, count)
|
|
87
87
|
undone = skipped.pop
|
|
88
88
|
|
|
89
|
-
raise
|
|
89
|
+
raise HistoryLimitError, 'End of redo history' if undone.nil?
|
|
90
90
|
|
|
91
91
|
redo_file = File.join(backup_dir, undone)
|
|
92
92
|
|
|
@@ -118,8 +118,7 @@ module Doing
|
|
|
118
118
|
filename ||= Doing.setting('doing_file')
|
|
119
119
|
|
|
120
120
|
undones = Dir.glob("undone*#{File.basename(filename)}", base: backup_dir).sort
|
|
121
|
-
|
|
122
|
-
raise DoingRuntimeError, 'End of redo history' if undones.empty?
|
|
121
|
+
raise HistoryLimitError, 'End of redo history' if undones.empty?
|
|
123
122
|
|
|
124
123
|
total = undones.count
|
|
125
124
|
options = undones.each_with_object([]) do |file, arr|
|
|
@@ -128,8 +127,7 @@ module Doing
|
|
|
128
127
|
|
|
129
128
|
arr.push("#{d.time_ago}\t#{File.join(backup_dir, file)}")
|
|
130
129
|
end
|
|
131
|
-
|
|
132
|
-
raise DoingRuntimeError, 'No backup files to load' if options.empty?
|
|
130
|
+
raise MissingBackupFile, 'No backup files to load' if options.empty?
|
|
133
131
|
|
|
134
132
|
backup_file = show_menu(options, filename)
|
|
135
133
|
idx = undones.index(File.basename(backup_file))
|
|
@@ -163,7 +161,7 @@ module Doing
|
|
|
163
161
|
arr.push("#{d.time_ago}\t#{File.join(backup_dir, file)}")
|
|
164
162
|
end
|
|
165
163
|
|
|
166
|
-
raise
|
|
164
|
+
raise MissingBackupFile, 'No backup files to load' if options.empty?
|
|
167
165
|
|
|
168
166
|
backup_file = show_menu(options, filename)
|
|
169
167
|
Util.write_to_file(File.join(backup_dir, "undone___#{File.basename(filename)}"), IO.read(filename), backup: false)
|
|
@@ -281,7 +279,7 @@ module Doing
|
|
|
281
279
|
def create_backup_dir
|
|
282
280
|
dir = File.expand_path(Doing.setting('backup_dir')) || File.join(user_home, '.doing_backup')
|
|
283
281
|
if File.exist?(dir) && !File.directory?(dir)
|
|
284
|
-
raise
|
|
282
|
+
raise DoingNoTraceError.new("#{dir} is not a directory", topic: 'History:', exit_code: 27)
|
|
285
283
|
|
|
286
284
|
end
|
|
287
285
|
|
data/lib/doing/version.rb
CHANGED
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doing
|
|
4
|
+
class WWID
|
|
5
|
+
# Display methods for WWID class
|
|
6
|
+
module Display
|
|
7
|
+
##
|
|
8
|
+
## Display contents of a section based on options
|
|
9
|
+
##
|
|
10
|
+
## @param opt [Hash] Additional Options
|
|
11
|
+
##
|
|
12
|
+
def list_section(opt, items: Items.new)
|
|
13
|
+
logger.benchmark(:list_section, :start)
|
|
14
|
+
opt[:config_template] ||= 'default'
|
|
15
|
+
|
|
16
|
+
tpl_cfg = Doing.setting(['templates', opt[:config_template]])
|
|
17
|
+
|
|
18
|
+
cfg = if opt[:view_template]
|
|
19
|
+
Doing.setting(['views', opt[:view_template]]).deep_merge(tpl_cfg, { extend_existing_arrays: true, sort_merged_arrays: true })
|
|
20
|
+
else
|
|
21
|
+
tpl_cfg
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
cfg.deep_merge({
|
|
25
|
+
'wrap_width' => Doing.setting('wrap_width') || 0,
|
|
26
|
+
'date_format' => Doing.setting('default_date_format'),
|
|
27
|
+
'order' => Doing.setting('order') || :asc,
|
|
28
|
+
'tags_color' => Doing.setting('tags_color'),
|
|
29
|
+
'duration' => Doing.setting('duration'),
|
|
30
|
+
'interval_format' => Doing.setting('interval_format')
|
|
31
|
+
}, { extend_existing_arrays: true, sort_merged_arrays: true })
|
|
32
|
+
|
|
33
|
+
opt[:duration] ||= cfg['duration'] || false
|
|
34
|
+
opt[:interval_format] ||= cfg['interval_format'] || 'text'
|
|
35
|
+
opt[:count] ||= 0
|
|
36
|
+
opt[:age] ||= :newest
|
|
37
|
+
opt[:age] = opt[:age].normalize_age
|
|
38
|
+
opt[:format] ||= cfg['date_format']
|
|
39
|
+
opt[:order] ||= cfg['order'] || :asc
|
|
40
|
+
opt[:tag_order] ||= :asc
|
|
41
|
+
opt[:tags_color] = cfg['tags_color'] || false if opt[:tags_color].nil?
|
|
42
|
+
opt[:template] ||= cfg['template']
|
|
43
|
+
opt[:sort_tags] ||= opt[:tag_sort]
|
|
44
|
+
|
|
45
|
+
# opt[:highlight] ||= true
|
|
46
|
+
title = ''
|
|
47
|
+
is_single = true
|
|
48
|
+
if opt[:section].nil?
|
|
49
|
+
opt[:section] = choose_section
|
|
50
|
+
title = opt[:section]
|
|
51
|
+
elsif opt[:section].instance_of?(String)
|
|
52
|
+
title = if opt[:section] =~ /^all$/i
|
|
53
|
+
if opt[:page_title]
|
|
54
|
+
opt[:page_title]
|
|
55
|
+
elsif opt[:tag_filter] && opt[:tag_filter]['bool'].normalize_bool != :not
|
|
56
|
+
opt[:tag_filter]['tags'].map { |tag| "@#{tag}" }.join(' + ')
|
|
57
|
+
else
|
|
58
|
+
'doing'
|
|
59
|
+
end
|
|
60
|
+
else
|
|
61
|
+
guess_section(opt[:section])
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
items = filter_items(items, opt: opt)
|
|
66
|
+
|
|
67
|
+
items.reverse! unless opt[:order].normalize_order == :desc
|
|
68
|
+
|
|
69
|
+
if opt[:delete]
|
|
70
|
+
delete_items(items, force: opt[:force])
|
|
71
|
+
|
|
72
|
+
write(@doing_file)
|
|
73
|
+
return
|
|
74
|
+
elsif opt[:editor]
|
|
75
|
+
edit_items(items)
|
|
76
|
+
|
|
77
|
+
write(@doing_file)
|
|
78
|
+
return
|
|
79
|
+
elsif opt[:interactive]
|
|
80
|
+
opt[:menu] = !opt[:force]
|
|
81
|
+
opt[:query] = '' # opt[:search]
|
|
82
|
+
opt[:multiple] = true
|
|
83
|
+
selected = Prompt.choose_from_items(items.reverse, include_section: opt[:section] =~ /^all$/i, **opt)
|
|
84
|
+
|
|
85
|
+
raise NoResults, 'no items selected' if selected.nil? || selected.empty?
|
|
86
|
+
|
|
87
|
+
act_on(selected, opt)
|
|
88
|
+
return
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
opt[:output] ||= 'template'
|
|
92
|
+
opt[:wrap_width] ||= Doing.setting('templates.default.wrap_width', 0)
|
|
93
|
+
|
|
94
|
+
logger.benchmark(:list_section, :finish)
|
|
95
|
+
output(items, title, is_single, opt)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
##
|
|
99
|
+
## Display entries within a date range
|
|
100
|
+
##
|
|
101
|
+
## @param dates [Array] [start, end]
|
|
102
|
+
## @param section [String] The section
|
|
103
|
+
## @param times (Bool) Show times
|
|
104
|
+
## @param output [String] Output format
|
|
105
|
+
## @param opt [Hash] Additional Options
|
|
106
|
+
##
|
|
107
|
+
def list_date(dates, section, times = nil, output = nil, opt)
|
|
108
|
+
opt ||= {}
|
|
109
|
+
opt[:totals] ||= false
|
|
110
|
+
opt[:sort_tags] ||= false
|
|
111
|
+
section = guess_section(section)
|
|
112
|
+
# :date_filter expects an array with start and end date
|
|
113
|
+
dates = dates.split_date_range if dates.instance_of?(String)
|
|
114
|
+
|
|
115
|
+
opt[:section] = section
|
|
116
|
+
opt[:count] = 0
|
|
117
|
+
opt[:order] = :asc
|
|
118
|
+
opt[:date_filter] = dates
|
|
119
|
+
opt[:times] = times
|
|
120
|
+
opt[:output] = output
|
|
121
|
+
|
|
122
|
+
time_rx = /^(\d{1,2}+(:\d{1,2}+)?( *(am|pm))?|midnight|noon)$/
|
|
123
|
+
if opt[:from] && opt[:from][0].is_a?(String) && opt[:from][0] =~ time_rx
|
|
124
|
+
opt[:time_filter] = opt[:from]
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
list_section(opt)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
##
|
|
131
|
+
## Show all entries from the current day
|
|
132
|
+
##
|
|
133
|
+
## @param times [Boolean] show times
|
|
134
|
+
## @param output [String] output format
|
|
135
|
+
## @param opt [Hash] Options
|
|
136
|
+
##
|
|
137
|
+
def today(times = true, output = nil, opt)
|
|
138
|
+
opt ||= {}
|
|
139
|
+
opt[:totals] ||= false
|
|
140
|
+
opt[:sort_tags] ||= false
|
|
141
|
+
|
|
142
|
+
cfg = Doing.setting('templates').deep_merge(Doing.setting('templates.default'), { extend_existing_arrays: true, sort_merged_arrays: true }).deep_merge({
|
|
143
|
+
'wrap_width' => Doing.setting('wrap_width') || 0,
|
|
144
|
+
'date_format' => Doing.setting('default_date_format'),
|
|
145
|
+
'order' => Doing.setting('order') || :asc,
|
|
146
|
+
'tags_color' => Doing.setting('tags_color'),
|
|
147
|
+
'duration' => Doing.setting('duration'),
|
|
148
|
+
'interval_format' => Doing.setting('interval_format')
|
|
149
|
+
}, { extend_existing_arrays: true, sort_merged_arrays: true })
|
|
150
|
+
|
|
151
|
+
template = opt[:template] || cfg['template']
|
|
152
|
+
|
|
153
|
+
opt[:duration] ||= cfg['duration'] || false
|
|
154
|
+
opt[:interval_format] ||= cfg['interval_format'] || 'text'
|
|
155
|
+
|
|
156
|
+
options = {
|
|
157
|
+
after: opt[:after],
|
|
158
|
+
before: opt[:before],
|
|
159
|
+
count: 0,
|
|
160
|
+
duration: opt[:duration],
|
|
161
|
+
from: opt[:from],
|
|
162
|
+
format: cfg['date_format'],
|
|
163
|
+
interval_format: opt[:interval_format],
|
|
164
|
+
only_timed: opt[:only_timed],
|
|
165
|
+
order: cfg['order'] || :asc,
|
|
166
|
+
output: output,
|
|
167
|
+
section: opt[:section],
|
|
168
|
+
sort_tags: opt[:sort_tags],
|
|
169
|
+
template: template,
|
|
170
|
+
times: times,
|
|
171
|
+
today: true,
|
|
172
|
+
totals: opt[:totals],
|
|
173
|
+
wrap_width: cfg['wrap_width'],
|
|
174
|
+
tags_color: cfg['tags_color'],
|
|
175
|
+
config_template: opt[:config_template]
|
|
176
|
+
}
|
|
177
|
+
list_section(options)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
##
|
|
181
|
+
## Show entries from the previous day
|
|
182
|
+
##
|
|
183
|
+
## @param section [String] The section
|
|
184
|
+
## @param times (Bool) Show times
|
|
185
|
+
## @param output [String] Output format
|
|
186
|
+
## @param opt [Hash] Additional Options
|
|
187
|
+
##
|
|
188
|
+
def yesterday(section, times = nil, output = nil, opt)
|
|
189
|
+
opt ||= {}
|
|
190
|
+
opt[:totals] ||= false
|
|
191
|
+
opt[:sort_tags] ||= false
|
|
192
|
+
opt[:config_template] ||= 'today'
|
|
193
|
+
opt[:yesterday] = true
|
|
194
|
+
|
|
195
|
+
section = guess_section(section)
|
|
196
|
+
y = (Time.now - (60 * 60 * 24)).strftime('%Y-%m-%d')
|
|
197
|
+
opt[:after] = "#{y} #{opt[:after]}" if opt[:after]
|
|
198
|
+
opt[:before] = "#{y} #{opt[:before]}" if opt[:before]
|
|
199
|
+
|
|
200
|
+
opt[:output] = output
|
|
201
|
+
opt[:section] = section
|
|
202
|
+
opt[:times] = times
|
|
203
|
+
opt[:count] = 0
|
|
204
|
+
|
|
205
|
+
list_section(opt)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
##
|
|
209
|
+
## Show recent entries
|
|
210
|
+
##
|
|
211
|
+
## @param count [Integer] The number to show
|
|
212
|
+
## @param section [String] The section to show from, default Currently
|
|
213
|
+
## @param opt [Hash] Additional Options
|
|
214
|
+
##
|
|
215
|
+
def recent(count = 10, section = nil, opt)
|
|
216
|
+
opt ||= {}
|
|
217
|
+
times = opt[:t] || true
|
|
218
|
+
opt[:totals] ||= false
|
|
219
|
+
opt[:sort_tags] ||= false
|
|
220
|
+
|
|
221
|
+
cfg = Doing.setting('templates.recent').deep_merge(Doing.setting('templates.default'), { extend_existing_arrays: true, sort_merged_arrays: true }).deep_merge({
|
|
222
|
+
'wrap_width' => Doing.setting('wrap_width') || 0,
|
|
223
|
+
'date_format' => Doing.setting('default_date_format'),
|
|
224
|
+
'order' => Doing.setting('order') || :asc,
|
|
225
|
+
'tags_color' => Doing.setting('tags_color'),
|
|
226
|
+
'duration' => Doing.setting('duration'),
|
|
227
|
+
'interval_format' => Doing.setting('interval_format')
|
|
228
|
+
}, { extend_existing_arrays: true, sort_merged_arrays: true })
|
|
229
|
+
opt[:duration] ||= cfg['duration'] || false
|
|
230
|
+
opt[:interval_format] ||= cfg['interval_format'] || 'text'
|
|
231
|
+
|
|
232
|
+
section ||= Doing.setting('current_section')
|
|
233
|
+
section = guess_section(section)
|
|
234
|
+
|
|
235
|
+
opt[:section] = section
|
|
236
|
+
opt[:wrap_width] = cfg['wrap_width']
|
|
237
|
+
opt[:count] = count
|
|
238
|
+
opt[:format] = cfg['date_format']
|
|
239
|
+
opt[:template] = opt[:template] || cfg['template']
|
|
240
|
+
opt[:order] = :asc
|
|
241
|
+
opt[:times] = times
|
|
242
|
+
|
|
243
|
+
list_section(opt)
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
##
|
|
247
|
+
## Show the last entry
|
|
248
|
+
##
|
|
249
|
+
## @param times (Bool) Show times
|
|
250
|
+
## @param section [String] Section to pull from, default Currently
|
|
251
|
+
##
|
|
252
|
+
def last(times: true, section: nil, options: {})
|
|
253
|
+
section = section.nil? || section =~ /all/i ? 'All' : guess_section(section)
|
|
254
|
+
cfg = Doing.setting(['templates', options[:config_template]]).deep_merge(Doing.setting('templates.default'), { extend_existing_arrays: true, sort_merged_arrays: true }).deep_merge({
|
|
255
|
+
'wrap_width' => Doing.setting('wrap_width', 0),
|
|
256
|
+
'date_format' => Doing.setting('default_date_format'),
|
|
257
|
+
'order' => Doing.setting('order', :asc),
|
|
258
|
+
'tags_color' => Doing.setting('tags_color'),
|
|
259
|
+
'duration' => Doing.setting('duration'),
|
|
260
|
+
'interval_format' => Doing.setting('interval_format')
|
|
261
|
+
}, { extend_existing_arrays: true, sort_merged_arrays: true })
|
|
262
|
+
options[:duration] ||= cfg['duration'] || false
|
|
263
|
+
options[:interval_format] ||= cfg['interval_format'] || 'text'
|
|
264
|
+
|
|
265
|
+
opts = {
|
|
266
|
+
case: options[:case],
|
|
267
|
+
config_template: options[:config_template] || 'last',
|
|
268
|
+
count: 1,
|
|
269
|
+
delete: options[:delete],
|
|
270
|
+
duration: options[:duration],
|
|
271
|
+
format: cfg['date_format'],
|
|
272
|
+
interval_format: options[:interval_format],
|
|
273
|
+
not: options[:negate],
|
|
274
|
+
output: options[:output],
|
|
275
|
+
section: section,
|
|
276
|
+
template: options[:template] || cfg['template'],
|
|
277
|
+
times: times,
|
|
278
|
+
val: options[:val],
|
|
279
|
+
wrap_width: cfg['wrap_width']
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if options[:tag]
|
|
283
|
+
opts[:tag_filter] = {
|
|
284
|
+
'tags' => options[:tag],
|
|
285
|
+
'bool' => options[:tag_bool]
|
|
286
|
+
}
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
opts[:search] = options[:search] if options[:search]
|
|
290
|
+
|
|
291
|
+
list_section(opts)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
##
|
|
295
|
+
## Return the content of the last note for a given section
|
|
296
|
+
##
|
|
297
|
+
## @param section [String] The section to retrieve from, default
|
|
298
|
+
## All
|
|
299
|
+
##
|
|
300
|
+
def last_note(section = 'All')
|
|
301
|
+
section = guess_section(section)
|
|
302
|
+
|
|
303
|
+
last_item = last_entry({ section: section })
|
|
304
|
+
|
|
305
|
+
raise NoEntryError, 'No entry found' unless last_item
|
|
306
|
+
|
|
307
|
+
logger.log_now(:info, 'Edit note:', last_item.title)
|
|
308
|
+
|
|
309
|
+
note = last_item.note&.to_s || ''
|
|
310
|
+
"#{last_item.title}\n# EDIT BELOW THIS LINE ------------\n#{note}"
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
##
|
|
314
|
+
## Get the last entry
|
|
315
|
+
##
|
|
316
|
+
## @param opt [Hash] Additional Options
|
|
317
|
+
##
|
|
318
|
+
def last_entry(opt)
|
|
319
|
+
opt ||= {}
|
|
320
|
+
opt[:tag_bool] ||= :and
|
|
321
|
+
opt[:section] ||= Doing.setting('current_section')
|
|
322
|
+
|
|
323
|
+
items = filter_items(Items.new, opt: opt)
|
|
324
|
+
|
|
325
|
+
logger.debug('Filtered:', "Parameters matched #{items.count} entries")
|
|
326
|
+
|
|
327
|
+
if opt[:interactive]
|
|
328
|
+
last_entry = Prompt.choose_from_items(items, include_section: opt[:section] =~ /^all$/i,
|
|
329
|
+
menu: true,
|
|
330
|
+
header: '',
|
|
331
|
+
prompt: 'Select an entry > ',
|
|
332
|
+
multiple: false,
|
|
333
|
+
sort: false,
|
|
334
|
+
show_if_single: true
|
|
335
|
+
)
|
|
336
|
+
else
|
|
337
|
+
last_entry = items.max_by { |item| item.date }
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
last_entry
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
private
|
|
344
|
+
|
|
345
|
+
##
|
|
346
|
+
## Generate output using available export plugins
|
|
347
|
+
##
|
|
348
|
+
## @param items [Array] The items
|
|
349
|
+
## @param title [String] Page title
|
|
350
|
+
## @param is_single [Boolean] Indicates if single
|
|
351
|
+
## section
|
|
352
|
+
## @param opt [Hash] Additional options
|
|
353
|
+
##
|
|
354
|
+
## @return [String] formatted output based on opt[:output]
|
|
355
|
+
## template trigger
|
|
356
|
+
## @api private
|
|
357
|
+
def output(items, title, is_single, opt)
|
|
358
|
+
logger.benchmark(:output, :start)
|
|
359
|
+
opt ||= {}
|
|
360
|
+
out = nil
|
|
361
|
+
|
|
362
|
+
raise InvalidArgument, 'Unknown output format' unless opt[:output] =~ Plugins.plugin_regex(type: :export)
|
|
363
|
+
|
|
364
|
+
export_options = { page_title: title, is_single: is_single, options: opt }
|
|
365
|
+
|
|
366
|
+
Hooks.trigger :pre_export, self, opt[:output], items
|
|
367
|
+
|
|
368
|
+
Plugins.plugins[:export].each do |_, options|
|
|
369
|
+
next unless opt[:output] =~ /^(#{options[:trigger].normalize_trigger})$/i
|
|
370
|
+
|
|
371
|
+
out = options[:class].render(self, items, variables: export_options)
|
|
372
|
+
break
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
logger.debug('Output:', "#{items.count} #{items.count == 1 ? 'item' : 'items'} shown")
|
|
376
|
+
logger.benchmark(:output, :finish)
|
|
377
|
+
out
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
##
|
|
381
|
+
## Get next item in the index
|
|
382
|
+
##
|
|
383
|
+
## @param item [Item] target item
|
|
384
|
+
## @param options [Hash] additional options
|
|
385
|
+
## @see #filter_items
|
|
386
|
+
##
|
|
387
|
+
## @return [Item] the next chronological item in the index
|
|
388
|
+
##
|
|
389
|
+
def next_item(item, options = {})
|
|
390
|
+
options ||= {}
|
|
391
|
+
items = filter_items(Items.new, opt: options)
|
|
392
|
+
|
|
393
|
+
idx = items.index(item)
|
|
394
|
+
|
|
395
|
+
idx.positive? ? items[idx - 1] : nil
|
|
396
|
+
end
|
|
397
|
+
end
|
|
398
|
+
end
|
|
399
|
+
end
|