doing 2.1.3 → 2.1.4pre
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/.yardoc/checksums +13 -10
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/CHANGELOG.md +27 -0
- data/Gemfile.lock +23 -1
- data/README.md +1 -1
- data/bin/doing +253 -63
- data/doc/Array.html +1 -1
- data/doc/Doing/Color.html +1 -1
- data/doc/Doing/Completion.html +1 -1
- data/doc/Doing/Configuration.html +42 -1
- data/doc/Doing/Errors/DoingNoTraceError.html +1 -1
- data/doc/Doing/Errors/DoingRuntimeError.html +1 -1
- data/doc/Doing/Errors/DoingStandardError.html +1 -1
- data/doc/Doing/Errors/EmptyInput.html +1 -1
- data/doc/Doing/Errors/NoResults.html +1 -1
- data/doc/Doing/Errors/PluginException.html +1 -1
- data/doc/Doing/Errors/UserCancelled.html +1 -1
- data/doc/Doing/Errors/WrongCommand.html +1 -1
- data/doc/Doing/Errors.html +1 -1
- data/doc/Doing/Hooks.html +1 -1
- data/doc/Doing/Item.html +37 -3
- data/doc/Doing/Items.html +35 -1
- data/doc/Doing/LogAdapter.html +1 -1
- data/doc/Doing/Note.html +1 -1
- data/doc/Doing/Pager.html +1 -1
- data/doc/Doing/Plugins.html +1 -1
- data/doc/Doing/Prompt.html +35 -1
- data/doc/Doing/Section.html +1 -1
- data/doc/Doing/Util.html +16 -4
- data/doc/Doing/WWID.html +131 -71
- data/doc/Doing.html +3 -3
- data/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
- data/doc/GLI/Commands.html +1 -1
- data/doc/GLI.html +1 -1
- data/doc/Hash.html +1 -1
- data/doc/Status.html +1 -1
- data/doc/String.html +104 -2
- data/doc/Symbol.html +1 -1
- data/doc/Time.html +70 -2
- data/doc/_index.html +125 -4
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +2 -2
- data/doc/index.html +2 -2
- data/doc/method_list.html +480 -144
- data/doc/top-level-namespace.html +2 -2
- data/doing.gemspec +2 -0
- data/doing.rdoc +155 -66
- data/lib/doing/boolean_term_parser.rb +86 -0
- data/lib/doing/configuration.rb +13 -4
- data/lib/doing/item.rb +94 -8
- data/lib/doing/items.rb +6 -0
- data/lib/doing/phrase_parser.rb +124 -0
- data/lib/doing/prompt.rb +8 -0
- data/lib/doing/string.rb +16 -2
- data/lib/doing/string_chronify.rb +5 -1
- data/lib/doing/time.rb +32 -0
- data/lib/doing/util.rb +2 -5
- data/lib/doing/util_backup.rb +235 -0
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +81 -26
- data/lib/doing.rb +6 -0
- metadata +47 -4
data/bin/doing
CHANGED
@@ -25,7 +25,7 @@ version Doing::VERSION
|
|
25
25
|
hide_commands_without_desc true
|
26
26
|
autocomplete_commands true
|
27
27
|
|
28
|
-
REGEX_BOOL = /^(?:and|all|any|or|not|none)$/i
|
28
|
+
REGEX_BOOL = /^(?:and|all|any|or|not|none|p(?:at(?:tern)?)?)$/i
|
29
29
|
REGEX_SORT_ORDER = /^(?:a(?:sc)?|d(?:esc)?)$/i
|
30
30
|
|
31
31
|
InvalidExportType = Class.new(RuntimeError)
|
@@ -195,7 +195,16 @@ command %i[now next] do |c|
|
|
195
195
|
end
|
196
196
|
|
197
197
|
desc 'Reset the start time of an entry'
|
198
|
+
long_desc 'Update the start time of the last entry or the last entry matching a tag/search filter.
|
199
|
+
If no argument is provided, the start time will be reset to the current time.
|
200
|
+
If a date string is provided as an argument, the start time will be set to the parsed result.'
|
201
|
+
arg_name 'DATE_STRING'
|
198
202
|
command %i[reset begin] do |c|
|
203
|
+
c.example 'doing reset', desc: 'Reset the start time of the last entry to the current time'
|
204
|
+
c.example 'doing reset --tag project1', desc: 'Reset the start time of the most recent entry tagged @project1 to the current time'
|
205
|
+
c.example 'doing reset 3pm', desc: 'Reset the start time of the last entry to 3pm of the current day'
|
206
|
+
c.example 'doing begin --tag todo --resume', desc: 'alias for reset. Updates the last @todo entry to the current time, removing @done tag.'
|
207
|
+
|
199
208
|
c.desc 'Limit search to section'
|
200
209
|
c.arg_name 'NAME'
|
201
210
|
c.flag %i[s section], default_value: 'All'
|
@@ -203,7 +212,7 @@ command %i[reset begin] do |c|
|
|
203
212
|
c.desc 'Resume entry (remove @done)'
|
204
213
|
c.switch %i[r resume], default_value: true
|
205
214
|
|
206
|
-
c.desc 'Reset last entry matching tag'
|
215
|
+
c.desc 'Reset last entry matching tag. Wildcards allowed (*, ?).'
|
207
216
|
c.arg_name 'TAG'
|
208
217
|
c.flag [:tag]
|
209
218
|
|
@@ -226,12 +235,19 @@ command %i[reset begin] do |c|
|
|
226
235
|
|
227
236
|
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
|
228
237
|
c.arg_name 'BOOLEAN'
|
229
|
-
c.flag [:bool], must_match: REGEX_BOOL, default_value: '
|
238
|
+
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
230
239
|
|
231
240
|
c.desc 'Select from a menu of matching entries'
|
232
241
|
c.switch %i[i interactive], negatable: false, default_value: false
|
233
242
|
|
234
243
|
c.action do |global_options, options, args|
|
244
|
+
if args.count > 0
|
245
|
+
reset_date = args.join(' ').chronify(guess: :begin)
|
246
|
+
raise InvalidArgument, 'Invalid date string' unless reset_date
|
247
|
+
else
|
248
|
+
reset_date = Time.now
|
249
|
+
end
|
250
|
+
|
235
251
|
options[:fuzzy] = false
|
236
252
|
if options[:section]
|
237
253
|
options[:section] = wwid.guess_section(options[:section]) || options[:section].cap_first
|
@@ -259,7 +275,7 @@ command %i[reset begin] do |c|
|
|
259
275
|
sort: false,
|
260
276
|
show_if_single: true)
|
261
277
|
else
|
262
|
-
last_entry = items.last
|
278
|
+
last_entry = items.reverse.last
|
263
279
|
end
|
264
280
|
|
265
281
|
unless last_entry
|
@@ -267,7 +283,7 @@ command %i[reset begin] do |c|
|
|
267
283
|
return
|
268
284
|
end
|
269
285
|
|
270
|
-
wwid.reset_item(last_entry, resume: options[:resume])
|
286
|
+
wwid.reset_item(last_entry, date: reset_date, resume: options[:resume])
|
271
287
|
|
272
288
|
# new_entry = Doing::Item.new(last_entry.date, last_entry.title, last_entry.section, new_note)
|
273
289
|
|
@@ -301,7 +317,7 @@ command :note do |c|
|
|
301
317
|
c.desc "Replace/Remove last entry's note (default append)"
|
302
318
|
c.switch %i[r remove], negatable: false, default_value: false
|
303
319
|
|
304
|
-
c.desc 'Add/remove note from last entry matching tag'
|
320
|
+
c.desc 'Add/remove note from last entry matching tag. Wildcards allowed (*, ?).'
|
305
321
|
c.arg_name 'TAG'
|
306
322
|
c.flag [:tag]
|
307
323
|
|
@@ -322,9 +338,9 @@ command :note do |c|
|
|
322
338
|
c.arg_name 'TYPE'
|
323
339
|
c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
|
324
340
|
|
325
|
-
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
|
341
|
+
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans.'
|
326
342
|
c.arg_name 'BOOLEAN'
|
327
|
-
c.flag [:bool], must_match: REGEX_BOOL, default_value: '
|
343
|
+
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
328
344
|
|
329
345
|
c.desc 'Select item for new note from a menu of matching entries'
|
330
346
|
c.switch %i[i interactive], negatable: false, default_value: false
|
@@ -394,6 +410,10 @@ command :note do |c|
|
|
394
410
|
end
|
395
411
|
|
396
412
|
desc 'Finish any running @meanwhile tasks and optionally create a new one'
|
413
|
+
long_desc 'The @meanwhile tag allows you to have long-running entries that encompass smaller entries.
|
414
|
+
This command makes it easy to start and stop these overarching entries. Just run `doing meanwhile Starting work on this
|
415
|
+
big project` to start a @meanwhile entry, add other entries as you work on the project, then use `doing meanwhile` by
|
416
|
+
itself to mark the entry as @done.'
|
397
417
|
arg_name 'ENTRY'
|
398
418
|
command :meanwhile do |c|
|
399
419
|
c.example 'doing meanwhile "Long task that will have others after it before it\'s done"', desc: 'Add a new long-running entry, completing any current @meanwhile entry'
|
@@ -521,8 +541,19 @@ long_desc 'List all entries and select with typeahead fuzzy matching.
|
|
521
541
|
|
522
542
|
Multiple selections are allowed, hit tab to add the highlighted entry to the
|
523
543
|
selection, and use ctrl-a to select all visible items. Return processes the
|
524
|
-
selected entries.
|
544
|
+
selected entries.
|
545
|
+
|
546
|
+
Search in the menu by typing:
|
547
|
+
|
548
|
+
sbtrkt fuzzy-match Items that match sbtrkt
|
549
|
+
|
550
|
+
\'wild exact-match (quoted) Items that include wild
|
551
|
+
|
552
|
+
!fire inverse-exact-match Items that do not include fire'
|
525
553
|
command :select do |c|
|
554
|
+
c.example 'doing select', desc: 'Select from all entries. A menu of available actions will be presented after confirming the selection.'
|
555
|
+
c.example 'doing select --editor', desc: 'Select entries from a menu and batch edit them in your default editor'
|
556
|
+
c.example 'doing select --after "yesterday 12pm" --tag project1', desc: 'Display a menu of entries created after noon yesterday, add @project1 to selected entries'
|
526
557
|
c.desc 'Select from a specific section'
|
527
558
|
c.arg_name 'SECTION'
|
528
559
|
c.flag %i[s section]
|
@@ -680,6 +711,9 @@ command :later do |c|
|
|
680
711
|
end
|
681
712
|
|
682
713
|
desc 'Add a completed item with @done(date). No argument finishes last entry.'
|
714
|
+
desc 'Use this command to add an entry after you\'ve already finished it. It will be immediately marked as @done.
|
715
|
+
You can modify the start and end times of the entry using the --back, --took, and --at flags, making it an easy
|
716
|
+
way to add entries in post and maintain accurate (albeit manual) time tracking.'
|
683
717
|
arg_name 'ENTRY'
|
684
718
|
command %i[done did] do |c|
|
685
719
|
c.example 'doing done', desc: 'Tag the last entry @done'
|
@@ -890,13 +924,13 @@ command :cancel do |c|
|
|
890
924
|
c.arg_name 'NAME'
|
891
925
|
c.flag %i[s section]
|
892
926
|
|
893
|
-
c.desc 'Cancel the last X entries containing TAG. Separate multiple tags with comma (--tag=tag1,tag2)'
|
927
|
+
c.desc 'Cancel the last X entries containing TAG. Separate multiple tags with comma (--tag=tag1,tag2). Wildcards allowed (*, ?).'
|
894
928
|
c.arg_name 'TAG'
|
895
929
|
c.flag [:tag]
|
896
930
|
|
897
|
-
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
|
931
|
+
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans.'
|
898
932
|
c.arg_name 'BOOLEAN'
|
899
|
-
c.flag [:bool], must_match: REGEX_BOOL, default_value: '
|
933
|
+
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
900
934
|
|
901
935
|
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")'
|
902
936
|
c.arg_name 'QUERY'
|
@@ -997,7 +1031,7 @@ command :finish do |c|
|
|
997
1031
|
c.flag [:at]
|
998
1032
|
|
999
1033
|
c.desc 'Finish the last X entries containing TAG.
|
1000
|
-
Separate multiple tags with comma (--tag=tag1,tag2), combine with --bool'
|
1034
|
+
Separate multiple tags with comma (--tag=tag1,tag2), combine with --bool. Wildcards allowed (*, ?).'
|
1001
1035
|
c.arg_name 'TAG'
|
1002
1036
|
c.flag [:tag]
|
1003
1037
|
|
@@ -1018,9 +1052,9 @@ command :finish do |c|
|
|
1018
1052
|
c.arg_name 'TYPE'
|
1019
1053
|
c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
|
1020
1054
|
|
1021
|
-
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
|
1055
|
+
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans.'
|
1022
1056
|
c.arg_name 'BOOLEAN'
|
1023
|
-
c.flag [:bool], must_match: REGEX_BOOL, default_value: '
|
1057
|
+
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
1024
1058
|
|
1025
1059
|
c.desc 'Remove done tag'
|
1026
1060
|
c.switch %i[r remove], negatable: false, default_value: false
|
@@ -1119,7 +1153,14 @@ command :finish do |c|
|
|
1119
1153
|
end
|
1120
1154
|
|
1121
1155
|
desc 'Repeat last entry as new entry'
|
1156
|
+
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.'
|
1122
1157
|
command %i[again resume] do |c|
|
1158
|
+
c.example 'doing resume', desc: 'Duplicate the most recent entry with a new start time, removing any @done tag'
|
1159
|
+
c.example 'doing again', desc: 'again is an alias for resume'
|
1160
|
+
c.example 'doing resume --editor', desc: 'Repeat the last entry, opening the new entry in the default editor'
|
1161
|
+
c.example 'doing resume --tag project1 --in Projects', desc: 'Repeat the last entry tagged @project1, creating the new entry in the Projects section'
|
1162
|
+
c.example 'doing resume --interactive', desc: 'Select the entry to repeat from a menu'
|
1163
|
+
|
1123
1164
|
c.desc 'Get last entry from a specific section'
|
1124
1165
|
c.arg_name 'NAME'
|
1125
1166
|
c.flag %i[s section], default_value: 'All'
|
@@ -1128,7 +1169,7 @@ command %i[again resume] do |c|
|
|
1128
1169
|
c.arg_name 'SECTION_NAME'
|
1129
1170
|
c.flag [:in]
|
1130
1171
|
|
1131
|
-
c.desc 'Repeat last entry matching tags. Combine multiple tags with a comma.'
|
1172
|
+
c.desc 'Repeat last entry matching tags. Combine multiple tags with a comma. Wildcards allowed (*, ?).'
|
1132
1173
|
c.arg_name 'TAG'
|
1133
1174
|
c.flag [:tag]
|
1134
1175
|
|
@@ -1150,9 +1191,9 @@ command %i[again resume] do |c|
|
|
1150
1191
|
c.arg_name 'TYPE'
|
1151
1192
|
c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
|
1152
1193
|
|
1153
|
-
c.desc 'Boolean used to combine multiple tags'
|
1194
|
+
c.desc 'Boolean used to combine multiple tags. Use PATTERN to parse + and - as booleans.'
|
1154
1195
|
c.arg_name 'BOOLEAN'
|
1155
|
-
c.flag [:bool], must_match: REGEX_BOOL, default_value: '
|
1196
|
+
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
1156
1197
|
|
1157
1198
|
c.desc "Edit duplicated entry with #{Doing::Util.default_editor} before adding"
|
1158
1199
|
c.switch %i[e editor], negatable: false, default_value: false
|
@@ -1186,6 +1227,46 @@ command %i[again resume] do |c|
|
|
1186
1227
|
end
|
1187
1228
|
end
|
1188
1229
|
|
1230
|
+
desc 'List all tags in the current Doing file'
|
1231
|
+
command :tags do |c|
|
1232
|
+
c.desc 'Section'
|
1233
|
+
c.arg_name 'SECTION_NAME'
|
1234
|
+
c.flag %i[s section], default_value: 'All'
|
1235
|
+
|
1236
|
+
c.desc 'Show count of occurrences'
|
1237
|
+
c.switch %i[c counts]
|
1238
|
+
|
1239
|
+
c.desc 'Sort by name or count'
|
1240
|
+
c.arg_name 'SORT_ORDER'
|
1241
|
+
c.flag %i[sort], default_value: 'name', must_match: /^(?:n(?:ame)?|c(?:ount)?)$/
|
1242
|
+
|
1243
|
+
c.desc 'Sort order (asc/desc)'
|
1244
|
+
c.arg_name 'ORDER'
|
1245
|
+
c.flag %i[o order], must_match: REGEX_SORT_ORDER, default_value: 'asc'
|
1246
|
+
|
1247
|
+
c.action do |_global, options, args|
|
1248
|
+
section = wwid.guess_section(options[:section]) || options[:section].cap_first
|
1249
|
+
|
1250
|
+
items = wwid.content.in_section(section)
|
1251
|
+
tags = wwid.all_tags(items, counts: true)
|
1252
|
+
|
1253
|
+
if options[:sort] =~ /^n/i
|
1254
|
+
tags = tags.sort_by { |tag, count| tag }
|
1255
|
+
else
|
1256
|
+
tags = tags.sort_by { |tag, count| count }
|
1257
|
+
end
|
1258
|
+
|
1259
|
+
tags.reverse! if options[:order].normalize_order == 'desc'
|
1260
|
+
|
1261
|
+
if options[:counts]
|
1262
|
+
tags.each { |t, c| puts "#{t} (#{c})" }
|
1263
|
+
else
|
1264
|
+
tags.each { |t, c| puts "#{t}" }
|
1265
|
+
end
|
1266
|
+
end
|
1267
|
+
end
|
1268
|
+
|
1269
|
+
|
1189
1270
|
desc 'Add tag(s) to last entry'
|
1190
1271
|
long_desc 'Add (or remove) tags from the last entry, or from multiple entries
|
1191
1272
|
(with `--count`), entries matching a search (with `--search`), or entries
|
@@ -1239,7 +1320,7 @@ command :tag do |c|
|
|
1239
1320
|
c.switch %i[a autotag], negatable: false, default_value: false
|
1240
1321
|
|
1241
1322
|
c.desc 'Tag the last X entries containing TAG.
|
1242
|
-
Separate multiple tags with comma (--tag=tag1,tag2), combine with --bool'
|
1323
|
+
Separate multiple tags with comma (--tag=tag1,tag2), combine with --bool. Wildcards allowed (*, ?).'
|
1243
1324
|
c.arg_name 'TAG'
|
1244
1325
|
c.flag [:tag]
|
1245
1326
|
|
@@ -1260,9 +1341,9 @@ command :tag do |c|
|
|
1260
1341
|
c.arg_name 'TYPE'
|
1261
1342
|
c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
|
1262
1343
|
|
1263
|
-
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
|
1344
|
+
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans.'
|
1264
1345
|
c.arg_name 'BOOLEAN'
|
1265
|
-
c.flag [:bool], must_match: REGEX_BOOL, default_value: '
|
1346
|
+
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
1266
1347
|
|
1267
1348
|
c.desc 'Select item(s) to tag from a menu of matching entries'
|
1268
1349
|
c.switch %i[i interactive], negatable: false, default_value: false
|
@@ -1350,8 +1431,9 @@ command :tag do |c|
|
|
1350
1431
|
end
|
1351
1432
|
|
1352
1433
|
desc 'Mark last entry as flagged'
|
1353
|
-
command [
|
1434
|
+
command %i[mark flag] do |c|
|
1354
1435
|
c.example 'doing flag', desc: 'Add @flagged to the last entry created'
|
1436
|
+
c.example 'doing mark', desc: 'mark is an alias for flag'
|
1355
1437
|
c.example 'doing flag --tag project1 --count 2', desc: 'Add @flagged to the last 2 entries tagged @project1'
|
1356
1438
|
c.example 'doing flag --interactive --search "/(develop|cod)ing/"', desc: 'Find entries matching regular expression and create a menu allowing multiple selections, selected items will be @flagged'
|
1357
1439
|
|
@@ -1376,7 +1458,7 @@ command [:mark, :flag] do |c|
|
|
1376
1458
|
c.switch %i[u unfinished], negatable: false, default_value: false
|
1377
1459
|
|
1378
1460
|
c.desc 'Flag the last entry containing TAG.
|
1379
|
-
Separate multiple tags with comma (--tag=tag1,tag2), combine with --bool'
|
1461
|
+
Separate multiple tags with comma (--tag=tag1,tag2), combine with --bool. Wildcards allowed (*, ?).'
|
1380
1462
|
c.arg_name 'TAG'
|
1381
1463
|
c.flag [:tag]
|
1382
1464
|
|
@@ -1397,9 +1479,9 @@ command [:mark, :flag] do |c|
|
|
1397
1479
|
c.arg_name 'TYPE'
|
1398
1480
|
c.flag [:case], must_match: /^[csi]/, default_value: 'smart'
|
1399
1481
|
|
1400
|
-
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
|
1482
|
+
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans.'
|
1401
1483
|
c.arg_name 'BOOLEAN'
|
1402
|
-
c.flag [:bool], must_match: REGEX_BOOL, default_value: '
|
1484
|
+
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
1403
1485
|
|
1404
1486
|
c.desc 'Select item(s) to flag from a menu of matching entries'
|
1405
1487
|
c.switch %i[i interactive], negatable: false, default_value: false
|
@@ -1473,7 +1555,11 @@ end
|
|
1473
1555
|
desc 'List all entries'
|
1474
1556
|
long_desc %(
|
1475
1557
|
The argument can be a section name, @tag(s) or both.
|
1476
|
-
"pick" or "choose" as an argument will offer a section menu.
|
1558
|
+
"pick" or "choose" as an argument will offer a section menu. Run with `--menu` to get a menu of available tags.
|
1559
|
+
|
1560
|
+
Show tags by passing @tagname arguments. Multiple tags can be combined, and you can specify the boolean used to
|
1561
|
+
combine them with `--bool (AND|OR|NOT)`. You can also use @+tagname to require a tag to match, or @-tagname to ignore
|
1562
|
+
entries containing tagname. +/- operators require `--bool PATTERN` (which is the default).
|
1477
1563
|
)
|
1478
1564
|
arg_name '[SECTION|@TAGS]'
|
1479
1565
|
command :show do |c|
|
@@ -1485,13 +1571,13 @@ command :show do |c|
|
|
1485
1571
|
c.example 'doing show Ideas @doing --from "mon to fri"', desc: 'Show entries tagged @doing from the Ideas section added between monday and friday of the current week.'
|
1486
1572
|
c.example 'doing show --interactive Later @doing', desc: 'Create a menu from entries from the Later section tagged @doing to perform batch actions'
|
1487
1573
|
|
1488
|
-
c.desc 'Tag filter, combine multiple tags with a comma. Added for compatibility with other commands.'
|
1574
|
+
c.desc 'Tag filter, combine multiple tags with a comma. Use `--tag pick` for a menu of available tags. Wildcards allowed (*, ?). Added for compatibility with other commands.'
|
1489
1575
|
c.arg_name 'TAG'
|
1490
1576
|
c.flag [:tag]
|
1491
1577
|
|
1492
|
-
c.desc 'Tag boolean (AND,OR,NOT)'
|
1578
|
+
c.desc 'Tag boolean (AND,OR,NOT). Use PATTERN to parse + and - as booleans.'
|
1493
1579
|
c.arg_name 'BOOLEAN'
|
1494
|
-
c.flag %i[b bool], must_match: REGEX_BOOL, default_value: '
|
1580
|
+
c.flag %i[b bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
1495
1581
|
|
1496
1582
|
c.desc 'Max count to show'
|
1497
1583
|
c.arg_name 'MAX'
|
@@ -1564,6 +1650,9 @@ command :show do |c|
|
|
1564
1650
|
c.desc 'Only show items with recorded time intervals'
|
1565
1651
|
c.switch [:only_timed], default_value: false, negatable: false
|
1566
1652
|
|
1653
|
+
c.desc 'Select section or tag to display from a menu'
|
1654
|
+
c.switch %i[m menu], negatable: false, default_value: false
|
1655
|
+
|
1567
1656
|
c.desc 'Select from a menu of matching entries to perform additional operations'
|
1568
1657
|
c.switch %i[i interactive], negatable: false, default_value: false
|
1569
1658
|
|
@@ -1576,15 +1665,17 @@ command :show do |c|
|
|
1576
1665
|
|
1577
1666
|
tag_filter = false
|
1578
1667
|
tags = []
|
1668
|
+
|
1579
1669
|
if args.length.positive?
|
1580
1670
|
case args[0]
|
1581
1671
|
when /^all$/i
|
1582
1672
|
section = 'All'
|
1583
1673
|
args.shift
|
1584
1674
|
when /^(choose|pick)$/i
|
1585
|
-
section = wwid.choose_section
|
1675
|
+
section = wwid.choose_section(include_all: true)
|
1676
|
+
|
1586
1677
|
args.shift
|
1587
|
-
when
|
1678
|
+
when /^[@+-]/
|
1588
1679
|
section = 'All'
|
1589
1680
|
else
|
1590
1681
|
begin
|
@@ -1607,7 +1698,14 @@ command :show do |c|
|
|
1607
1698
|
end
|
1608
1699
|
end
|
1609
1700
|
else
|
1610
|
-
section = settings['current_section']
|
1701
|
+
section = options[:menu] ? wwid.choose_section(include_all: true) : settings['current_section']
|
1702
|
+
end
|
1703
|
+
|
1704
|
+
if options[:menu]
|
1705
|
+
tag = wwid.choose_tag(section, include_all: true)
|
1706
|
+
raise UserCancelled unless tag
|
1707
|
+
|
1708
|
+
tags.concat(tag.split(/ +/).map { |t| t.strip.sub(/^@/, '') }) if tag =~ /^@/
|
1611
1709
|
end
|
1612
1710
|
|
1613
1711
|
tags.concat(options[:tag].to_tags) if options[:tag]
|
@@ -1652,11 +1750,11 @@ command :show do |c|
|
|
1652
1750
|
end
|
1653
1751
|
|
1654
1752
|
desc 'Search for entries'
|
1655
|
-
long_desc
|
1656
|
-
|
1753
|
+
long_desc %(
|
1754
|
+
Search all sections (or limit to a single section) for entries matching text or regular expression. Normal strings are fuzzy matched.
|
1657
1755
|
|
1658
|
-
|
1659
|
-
|
1756
|
+
To search with regular expressions, single quote the string and surround with slashes: `doing search '/\bm.*?x\b/'`
|
1757
|
+
)
|
1660
1758
|
|
1661
1759
|
arg_name 'SEARCH_PATTERN'
|
1662
1760
|
command %i[grep search] do |c|
|
@@ -1820,6 +1918,8 @@ command :recent do |c|
|
|
1820
1918
|
end
|
1821
1919
|
|
1822
1920
|
desc 'List entries from today'
|
1921
|
+
long_desc 'List entries from the current day. Use --before, --after, and
|
1922
|
+
--from to specify time ranges.'
|
1823
1923
|
command :today do |c|
|
1824
1924
|
c.example 'doing today', desc: 'List all entries with start dates between 12am and 11:59PM for the current day'
|
1825
1925
|
c.example 'doing today --section Later', desc: 'List today\'s entries in the Later section'
|
@@ -1994,6 +2094,8 @@ command :since do |c|
|
|
1994
2094
|
end
|
1995
2095
|
|
1996
2096
|
desc 'List entries from yesterday'
|
2097
|
+
desc 'Show only entries with start times within the previous 24 hour period. Use --before, --after, and --from to limit to
|
2098
|
+
time spans within the day.'
|
1997
2099
|
command :yesterday do |c|
|
1998
2100
|
c.example 'doing yesterday', desc: 'List all entries from the previous day'
|
1999
2101
|
c.example 'doing yesterday --after 8am --before 5pm', desc: 'List entries from the previous day between 8am and 5pm'
|
@@ -2065,6 +2167,8 @@ command :yesterday do |c|
|
|
2065
2167
|
end
|
2066
2168
|
|
2067
2169
|
desc 'Show the last entry, optionally edit'
|
2170
|
+
long_desc 'Shows the last entry. Using --search and --tag filters, you can view/edit the last entry matching a filter,
|
2171
|
+
allowing `doing last` to target historical entries.'
|
2068
2172
|
command :last do |c|
|
2069
2173
|
c.example 'doing last', desc: 'Show the most recent entry in all sections'
|
2070
2174
|
c.example 'doing last -s Later', desc: 'Show the most recent entry in the Later section'
|
@@ -2081,13 +2185,13 @@ command :last do |c|
|
|
2081
2185
|
c.desc "Edit entry with #{Doing::Util.default_editor}"
|
2082
2186
|
c.switch %i[e editor], negatable: false, default_value: false
|
2083
2187
|
|
2084
|
-
c.desc 'Tag filter, combine multiple tags with a comma.'
|
2188
|
+
c.desc 'Tag filter, combine multiple tags with a comma. Wildcards allowed (*, ?).'
|
2085
2189
|
c.arg_name 'TAG'
|
2086
2190
|
c.flag [:tag]
|
2087
2191
|
|
2088
|
-
c.desc 'Tag boolean'
|
2192
|
+
c.desc 'Tag boolean (AND|OR|NOT). Use PATTERN to parse + and - as booleans.'
|
2089
2193
|
c.arg_name 'BOOLEAN'
|
2090
|
-
c.flag [:bool], must_match: REGEX_BOOL, default_value: '
|
2194
|
+
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
2091
2195
|
|
2092
2196
|
c.desc 'Search filter, surround with slashes for regex (/query/), start with single quote for exact match ("\'query")'
|
2093
2197
|
c.arg_name 'QUERY'
|
@@ -2118,6 +2222,8 @@ command :last do |c|
|
|
2118
2222
|
else
|
2119
2223
|
tags = options[:tag].to_tags
|
2120
2224
|
options[:bool] = case options[:bool]
|
2225
|
+
when /^p/i
|
2226
|
+
:pattern
|
2121
2227
|
when /(any|or)/i
|
2122
2228
|
:or
|
2123
2229
|
when /(not|none)/i
|
@@ -2230,6 +2336,8 @@ command :plugins do |c|
|
|
2230
2336
|
end
|
2231
2337
|
|
2232
2338
|
desc 'Generate shell completion scripts'
|
2339
|
+
desc 'Generates the necessary scripts to add command line completion to various shells, so typing \'doing\' and hitting
|
2340
|
+
tab will offer completions of subcommands and their options.'
|
2233
2341
|
command :completion do |c|
|
2234
2342
|
c.example 'doing completion', desc: 'Output zsh (default) to STDOUT'
|
2235
2343
|
c.example 'doing completion --type zsh --file ~/.zsh-completions/_doing.zsh', desc: 'Output zsh completions to file'
|
@@ -2252,7 +2360,8 @@ command :completion do |c|
|
|
2252
2360
|
end
|
2253
2361
|
|
2254
2362
|
desc 'Display a user-created view'
|
2255
|
-
long_desc '
|
2363
|
+
long_desc 'Views are defined in your configuration (use `doing config` to edit).
|
2364
|
+
Command line options override view configuration.'
|
2256
2365
|
arg_name 'VIEW_NAME'
|
2257
2366
|
command :view do |c|
|
2258
2367
|
c.example 'doing view color', desc: 'Display entries according to config for view "color"'
|
@@ -2282,13 +2391,13 @@ command :view do |c|
|
|
2282
2391
|
c.desc 'Include colors in output'
|
2283
2392
|
c.switch [:color], default_value: true, negatable: true
|
2284
2393
|
|
2285
|
-
c.desc 'Tag filter, combine multiple tags with a comma.'
|
2394
|
+
c.desc 'Tag filter, combine multiple tags with a comma. Wildcards allowed (*, ?).'
|
2286
2395
|
c.arg_name 'TAG'
|
2287
2396
|
c.flag [:tag]
|
2288
2397
|
|
2289
|
-
c.desc 'Tag boolean (AND,OR,NOT)'
|
2398
|
+
c.desc 'Tag boolean (AND,OR,NOT). Use PATTERN to parse + and - as booleans.'
|
2290
2399
|
c.arg_name 'BOOLEAN'
|
2291
|
-
c.flag %i[b bool], must_match: REGEX_BOOL, default_value: '
|
2400
|
+
c.flag %i[b bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
2292
2401
|
|
2293
2402
|
c.desc 'Search filter, surround with slashes for regex (/query/), start with single quote for exact match ("\'query")'
|
2294
2403
|
c.arg_name 'QUERY'
|
@@ -2382,16 +2491,22 @@ command :view do |c|
|
|
2382
2491
|
tag_filter = false
|
2383
2492
|
if options[:tag]
|
2384
2493
|
tag_filter = { 'tags' => [], 'bool' => 'OR' }
|
2385
|
-
|
2386
|
-
tag_filter['bool'] =
|
2494
|
+
bool = options[:bool].normalize_bool
|
2495
|
+
tag_filter['bool'] = bool
|
2496
|
+
tag_filter['tags'] = if bool == :pattern
|
2497
|
+
options[:tag]
|
2498
|
+
else
|
2499
|
+
options[:tag].gsub(/[, ]+/, ' ').split(' ').map(&:strip)
|
2500
|
+
end
|
2387
2501
|
elsif view.key?('tags') && !(view['tags'].nil? || view['tags'].empty?)
|
2388
2502
|
tag_filter = { 'tags' => [], 'bool' => 'OR' }
|
2503
|
+
bool = view.key?('tags_bool') && !view['tags_bool'].nil? ? view['tags_bool'].normalize_bool : :pattern
|
2504
|
+
tag_filter['bool'] = bool
|
2389
2505
|
tag_filter['tags'] = if view['tags'].instance_of?(Array)
|
2390
|
-
view['tags'].map(&:strip)
|
2506
|
+
bool == :pattern ? view['tags'].join(' ').strip : view['tags'].map(&:strip)
|
2391
2507
|
else
|
2392
|
-
view['tags'].gsub(/[, ]+/, ' ').split(' ').map(&:strip)
|
2508
|
+
bool == :pattern ? view['tags'].strip : view['tags'].gsub(/[, ]+/, ' ').split(' ').map(&:strip)
|
2393
2509
|
end
|
2394
|
-
tag_filter['bool'] = view.key?('tags_bool') && !view['tags_bool'].nil? ? view['tags_bool'].normalize_bool : :or
|
2395
2510
|
end
|
2396
2511
|
|
2397
2512
|
# If the -o/--output flag was specified, override any default in the view template
|
@@ -2500,13 +2615,13 @@ command %i[archive move] do |c|
|
|
2500
2615
|
c.desc 'Label moved items with @from(SECTION_NAME)'
|
2501
2616
|
c.switch [:label], default_value: true, negatable: true
|
2502
2617
|
|
2503
|
-
c.desc 'Tag filter, combine multiple tags with a comma. Added for compatibility with other commands.'
|
2618
|
+
c.desc 'Tag filter, combine multiple tags with a comma. Wildcards allowed (*, ?). Added for compatibility with other commands.'
|
2504
2619
|
c.arg_name 'TAG'
|
2505
2620
|
c.flag [:tag]
|
2506
2621
|
|
2507
|
-
c.desc 'Tag boolean (AND|OR|NOT)'
|
2622
|
+
c.desc 'Tag boolean (AND|OR|NOT). Use PATTERN to parse + and - as booleans.'
|
2508
2623
|
c.arg_name 'BOOLEAN'
|
2509
|
-
c.flag [:bool], must_match: REGEX_BOOL, default_value: '
|
2624
|
+
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
2510
2625
|
|
2511
2626
|
c.desc 'Search filter'
|
2512
2627
|
c.arg_name 'QUERY'
|
@@ -2569,6 +2684,9 @@ command %i[archive move] do |c|
|
|
2569
2684
|
end
|
2570
2685
|
|
2571
2686
|
desc 'Move entries to archive file'
|
2687
|
+
long_desc 'As your doing file grows, commands can get slow. Given that your historical data (and your archive section)
|
2688
|
+
probably aren\'t providing any useful insights a year later, use this command to "rotate" old entries out to an archive
|
2689
|
+
file. You\'ll still have access to all historical data, but it won\'t be slowing down daily operation.'
|
2572
2690
|
command :rotate do |c|
|
2573
2691
|
c.example 'doing rotate', desc: 'Move all entries in doing file to a dated secondary file'
|
2574
2692
|
c.example 'doing rotate --section Archive --keep 10', desc: 'Move entries in the Archive section to a secondary file, keeping the most recent 10 entries'
|
@@ -2582,13 +2700,13 @@ command :rotate do |c|
|
|
2582
2700
|
c.arg_name 'SECTION_NAME'
|
2583
2701
|
c.flag %i[s section], default_value: 'All'
|
2584
2702
|
|
2585
|
-
c.desc 'Tag filter, combine multiple tags with a comma. Added for compatibility with other commands.'
|
2703
|
+
c.desc 'Tag filter, combine multiple tags with a comma. Wildcards allowed (*, ?). Added for compatibility with other commands.'
|
2586
2704
|
c.arg_name 'TAG'
|
2587
2705
|
c.flag [:tag]
|
2588
2706
|
|
2589
|
-
c.desc 'Tag boolean (AND|OR|NOT)'
|
2707
|
+
c.desc 'Tag boolean (AND|OR|NOT). Use PATTERN to parse + and - as booleans.'
|
2590
2708
|
c.arg_name 'BOOLEAN'
|
2591
|
-
c.flag [:bool], must_match: REGEX_BOOL, default_value: '
|
2709
|
+
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
2592
2710
|
|
2593
2711
|
c.desc 'Search filter'
|
2594
2712
|
c.arg_name 'QUERY'
|
@@ -2635,8 +2753,10 @@ command :rotate do |c|
|
|
2635
2753
|
end
|
2636
2754
|
|
2637
2755
|
desc 'Open the "doing" file in an editor'
|
2638
|
-
long_desc "`doing open` defaults to using the
|
2756
|
+
long_desc "`doing open` defaults to using the editors->doing_file setting
|
2757
|
+
in #{config.config_file} (#{Doing::Util.find_default_editor('doing_file')})."
|
2639
2758
|
command :open do |c|
|
2759
|
+
c.example 'doing open', desc: 'Open the doing file in the default editor'
|
2640
2760
|
c.desc 'Open with editor command (e.g. vim, mate)'
|
2641
2761
|
c.arg_name 'COMMAND'
|
2642
2762
|
c.flag %i[e editor]
|
@@ -2885,6 +3005,7 @@ command :config do |c|
|
|
2885
3005
|
real_path = config.resolve_key_path(keypath, create: true)
|
2886
3006
|
|
2887
3007
|
old_value = settings.dig(*real_path) || nil
|
3008
|
+
old_type = old_value&.class.to_s || nil
|
2888
3009
|
|
2889
3010
|
if old_value.is_a?(Hash) && !options[:remove]
|
2890
3011
|
Doing.logger.log_now(:warn, 'Config:', "Config key must point to a single value, #{real_path.join('->').boldwhite} is a mapping")
|
@@ -2906,13 +3027,11 @@ command :config do |c|
|
|
2906
3027
|
cfg.deep_set(real_path, nil)
|
2907
3028
|
$stderr.puts "#{'Deleting key:'.yellow} #{real_path.join('->').boldwhite}"
|
2908
3029
|
else
|
2909
|
-
|
2910
|
-
p real_path
|
2911
|
-
cfg.deep_set(real_path, value.set_type)
|
3030
|
+
cfg.deep_set(real_path, value.set_type(old_type))
|
2912
3031
|
|
2913
3032
|
$stderr.puts "#{'Key path:'.yellow} #{real_path.join('->').boldwhite}"
|
2914
|
-
$stderr.puts "#{'Previous:'.yellow} #{(old_value ? old_value
|
2915
|
-
$stderr.puts "#{' New:'.yellow} #{value.set_type.to_s.boldwhite}"
|
3033
|
+
$stderr.puts "#{'Previous:'.yellow} #{(old_value ? old_value.to_s : 'empty').boldwhite}"
|
3034
|
+
$stderr.puts "#{' New:'.yellow} #{value.set_type(old_type).to_s.boldwhite}"
|
2916
3035
|
end
|
2917
3036
|
|
2918
3037
|
res = Doing::Prompt.yn('Update selected config', default_response: true)
|
@@ -2925,15 +3044,79 @@ command :config do |c|
|
|
2925
3044
|
end
|
2926
3045
|
end
|
2927
3046
|
|
2928
|
-
desc 'Undo the last
|
3047
|
+
desc 'Undo the last X changes to the Doing file'
|
3048
|
+
long_desc 'Reverts the last X commands that altered the doing file.
|
3049
|
+
All changes performed by a single command are undone at once.
|
3050
|
+
|
3051
|
+
Specify a number to jump back multiple revisions, or use --select for an interactive menu.'
|
3052
|
+
arg_name 'COUNT'
|
2929
3053
|
command :undo do |c|
|
3054
|
+
c.example 'doing undo', desc: 'Undo the most recent change to the doing file'
|
3055
|
+
c.example 'doing undo 5', desc: 'Undo the last 5 changes to the doing file'
|
3056
|
+
c.example 'doing undo --interactive', desc: 'Select from a menu of available revisions'
|
3057
|
+
c.example 'doing undo --redo', desc: 'Undo the last undo command'
|
3058
|
+
|
2930
3059
|
c.desc 'Specify alternate doing file'
|
2931
3060
|
c.arg_name 'PATH'
|
2932
3061
|
c.flag %i[f file], default_value: wwid.doing_file
|
2933
3062
|
|
2934
|
-
c.
|
3063
|
+
c.desc 'Select from recent backups'
|
3064
|
+
c.switch %i[i interactive], negatable: false
|
3065
|
+
|
3066
|
+
c.desc 'Remove old backups, retaining X files'
|
3067
|
+
c.arg_name 'COUNT'
|
3068
|
+
c.flag %i[p prune], type: Integer
|
3069
|
+
|
3070
|
+
c.desc 'Redo last undo. Note: you cannot undo a redo.'
|
3071
|
+
c.switch %i[r redo]
|
3072
|
+
|
3073
|
+
c.action do |_global_options, options, args|
|
2935
3074
|
file = options[:file] || wwid.doing_file
|
2936
|
-
|
3075
|
+
count = args.empty? ? 1 : args[0].to_i
|
3076
|
+
raise InvalidArgument, "Invalid count specified for undo" unless count&.positive?
|
3077
|
+
|
3078
|
+
if options[:prune]
|
3079
|
+
Doing::Util::Backup.prune_backups(file, options[:prune])
|
3080
|
+
elsif options[:redo]
|
3081
|
+
Doing::Util::Backup.redo_backup(file, count: count)
|
3082
|
+
else
|
3083
|
+
if options[:interactive]
|
3084
|
+
Doing::Util::Backup.select_backup(file)
|
3085
|
+
else
|
3086
|
+
Doing::Util::Backup.restore_last_backup(file, count: count)
|
3087
|
+
end
|
3088
|
+
end
|
3089
|
+
end
|
3090
|
+
end
|
3091
|
+
|
3092
|
+
long_desc 'Shortcut for `doing undo -r`, reverses the last undo command. You cannot undo a redo.'
|
3093
|
+
arg_name 'COUNT'
|
3094
|
+
command :redo do |c|
|
3095
|
+
c.desc 'Specify alternate doing file'
|
3096
|
+
c.arg_name 'PATH'
|
3097
|
+
c.flag %i[f file], default_value: wwid.doing_file
|
3098
|
+
|
3099
|
+
c.action do |_global, options, args|
|
3100
|
+
file = options[:file] || wwid.doing_file
|
3101
|
+
count = args.empty? ? 1 : args[0].to_i
|
3102
|
+
raise InvalidArgument, "Invalid count specified for redo" unless count&.positive?
|
3103
|
+
|
3104
|
+
Doing::Util::Backup.redo_backup(file, count: count)
|
3105
|
+
end
|
3106
|
+
end
|
3107
|
+
|
3108
|
+
desc 'List recent changes in Doing'
|
3109
|
+
long_desc 'Display a formatted list of changes in recent versions, latest at the top'
|
3110
|
+
command %i[changelog changes] do |c|
|
3111
|
+
c.action do |_global_options, options, args|
|
3112
|
+
changelog = File.expand_path(File.join(File.dirname(__FILE__), '..', 'CHANGELOG.md'))
|
3113
|
+
if File.exist?(changelog)
|
3114
|
+
parsed = TTY::Markdown.parse(IO.read(changelog), width: 80, symbols: {override: {bullet: "•"}})
|
3115
|
+
Doing::Pager.paginate = true
|
3116
|
+
Doing::Pager.page parsed
|
3117
|
+
else
|
3118
|
+
raise "Error locating changelog"
|
3119
|
+
end
|
2937
3120
|
end
|
2938
3121
|
end
|
2939
3122
|
|
@@ -2941,6 +3124,10 @@ desc 'Import entries from an external source'
|
|
2941
3124
|
long_desc "Imports entries from other sources. Available plugins: #{Doing::Plugins.plugin_names(type: :import, separator: ', ')}"
|
2942
3125
|
arg_name 'PATH'
|
2943
3126
|
command :import do |c|
|
3127
|
+
c.example 'doing import --type timing "~/Desktop/All Activities.json"', desc: 'Import a Timing.app JSON report'
|
3128
|
+
c.example 'doing import --type doing --tag imported --no-autotag ~/doing_backup.md', desc: 'Import an Doing archive, tag all entries with @imported, skip autotagging'
|
3129
|
+
c.example 'doing import --type doing --from "10/1 to 10/15" ~/doing_backup.md', desc: 'Import a Doing archive, only importing entries between two dates'
|
3130
|
+
|
2944
3131
|
c.desc "Import type (#{Doing::Plugins.plugin_names(type: :import)})"
|
2945
3132
|
c.arg_name 'TYPE'
|
2946
3133
|
c.flag :type, default_value: 'doing'
|
@@ -3080,10 +3267,13 @@ around do |global, command, options, arguments, code|
|
|
3080
3267
|
|
3081
3268
|
if global[:yes]
|
3082
3269
|
Doing::Prompt.force_answer = true
|
3270
|
+
Doing.config.force_answer = true
|
3083
3271
|
elsif global[:no]
|
3084
3272
|
Doing::Prompt.force_answer = false
|
3273
|
+
Doing.config.force_answer = false
|
3085
3274
|
else
|
3086
3275
|
Doing::Prompt.default_answer = global[:default]
|
3276
|
+
Doing.config.force_answer = global[:default] ? true : false
|
3087
3277
|
end
|
3088
3278
|
|
3089
3279
|
if global[:config_file] && global[:config_file] != config.config_file
|