doing 1.0.51 → 1.0.56
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +35 -9
- data/bin/doing +754 -578
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +221 -86
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a0efeeb7339da1578053099b2638ff6ca1e6319520a24b536381ca40a33e330
|
4
|
+
data.tar.gz: e6507789ad1e43fce7e1627075fb4fc578f0a6c0630907ef78b469b05c09fc4d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9914f2d9be6d9fbba69eaf67c316252186c712816e48cfb45acd7e278556f1e7769047b984a6e08fe8af36156d7bddb247f476685dcdbd3a375c28d4a0780172
|
7
|
+
data.tar.gz: 53a81b430e70ceebf7f1d284d97a4579d0e29eea714a11380b1fa0dd526c98c2e94b9fef3edbc047e7f65b4df1c631d803840191d961738d2ed78e132ec72ba5
|
data/README.md
CHANGED
@@ -4,7 +4,6 @@
|
|
4
4
|
|
5
5
|
_If you're one of the rare people like me who find this useful, feel free to [buy me some coffee](http://brettterpstra.com/donate/)._
|
6
6
|
|
7
|
-
|
8
7
|
## Contents
|
9
8
|
|
10
9
|
- [What and why](#what-and-why)
|
@@ -16,7 +15,7 @@ _If you're one of the rare people like me who find this useful, feel free to [bu
|
|
16
15
|
- [Troubleshooting](#troubleshooting)
|
17
16
|
- [Changelog](#changelog)
|
18
17
|
|
19
|
-
<!--
|
18
|
+
<!--README-->
|
20
19
|
|
21
20
|
## What and why
|
22
21
|
|
@@ -30,6 +29,8 @@ _Side note:_ I actually use the library behind this utility as part of another s
|
|
30
29
|
|
31
30
|
## Installation
|
32
31
|
|
32
|
+
The current version of `doing` is <!--VER-->1.0.55<!--END VER-->.
|
33
|
+
|
33
34
|
$ [sudo] gem install doing
|
34
35
|
|
35
36
|
To install the _latest_ version, use `--pre`:
|
@@ -67,8 +68,10 @@ A basic configuration looks like this:
|
|
67
68
|
default_date_format: '%Y-%m-%d %H:%M'
|
68
69
|
marker_tag: flagged
|
69
70
|
marker_color: yellow
|
71
|
+
tags_color: boldcyan
|
70
72
|
default_tags: []
|
71
|
-
editor_app:
|
73
|
+
editor_app: TaskPaper
|
74
|
+
config_editor_app: Sublime Text
|
72
75
|
:include_notes: true
|
73
76
|
views:
|
74
77
|
color:
|
@@ -137,7 +140,9 @@ You can rename the section that holds your current tasks. By default, this is `C
|
|
137
140
|
|
138
141
|
### Default editors
|
139
142
|
|
140
|
-
The setting `editor_app` only applies to Mac OS X users. It's the default application that the command `doing open` will open your WWID file in. If this is blank, it will be opened by whatever the system default is, or you can use `-a app_name` or `-b bundle_id` to override.
|
143
|
+
The setting `editor_app` only applies to Mac OS X users. It's the default application that the command `doing open` will open your WWID file in. Personally, I use `editor_app: TaskPaper`. If this is blank, it will be opened by whatever the system default is for the doing file extension (default is `.md`), or you can use `-a app_name` or `-b bundle_id` to override.
|
144
|
+
|
145
|
+
You can define a separate app to open the config file in when running `doing config`. The key for this is `config_editor_app`.
|
141
146
|
|
142
147
|
In the case of the `doing now -e` command, your `$EDITOR` environment variable will be used to complete the entry text and notes. Set it in your `~/.bash_profile` or whatever is appropriate for your system:
|
143
148
|
|
@@ -413,6 +418,8 @@ When used with `doing done`, `--back` and `--took` allow time intervals to be ac
|
|
413
418
|
|
414
419
|
All of these commands accept a `-e` argument. This opens your command line editor (as defined in the environment variable `$EDITOR`). Add your entry, save the temp file, and close it. The new entry is added. Anything after the first line is included as a note on the entry.
|
415
420
|
|
421
|
+
`doing again` (or `doing resume`) will duplicate the last @done entry (most recently completed) with a new start date (and without the @done tag). To resume the last entry matching specific tags, use `--tag=TAG`. You can specify multiple tags by separating with a comma. Multiple tags are combined with 'AND' by default (all tags must exist on the entry to match), but you can use `--bool=` to set it to 'OR' or 'NOT'. By default the new entry will be added to the same section as the matching entry, but you can specify a section with `--in=SECTION`.
|
422
|
+
|
416
423
|
`doing meanwhile` is a special command for creating and finishing tasks that may have other entries come before they're complete. When you create an entry with `doing meanwhile [entry text]`, it will automatically complete the last _@meanwhile_ item (dated _@done_ tag) and add the _@meanwhile_ tag to the new item. This allows time tracking on a more general basis, and still lets you keep track of the smaller things you do while working on an overarching project. The `meanwhile` command accepts `--back [time]` and will backdate the _@done_ tag and start date of the new task at the same time. Running `meanwhile` with no arguments will simply complete the last _@meanwhile_ task.
|
417
424
|
|
418
425
|
See `doing help meanwhile` for more options.
|
@@ -438,9 +445,9 @@ You can finish the last entry containing a specific tag or combination of tags u
|
|
438
445
|
|
439
446
|
doing finish --tag=work,project1
|
440
447
|
|
441
|
-
You can change the boolean using `--
|
448
|
+
You can change the boolean using `--bool=OR` (last entry containing any of the specified tags) or `--bool=NOT` (last entry containing none of the tags).
|
442
449
|
|
443
|
-
You can also include a `--no-date` switch to add `@done` without a finish date, meaning no time is tracked for the task. `doing cancel` is an alias for this. Like `finish`, `cancel` accepts a count to act on the last X entries, as well as `--archive` and `--section` options.
|
450
|
+
You can also include a `--no-date` switch to add `@done` without a finish date, meaning no time is tracked for the task. `doing cancel` is an alias for this. Like `finish`, `cancel` accepts a count to act on the last X entries, as well as `--archive` and `--section` options. `cancel` also accepts the `--tag` and `--bool` flags for tag filtering.
|
444
451
|
|
445
452
|
|
446
453
|
##### Tagging and Autotagging
|
@@ -492,6 +499,8 @@ This creates a search pattern looking for a string of word characters followed b
|
|
492
499
|
|
493
500
|
You can also add notes at the time of entry by using the `-n` or `--note` flag with `doing now`, `doing later`, or `doing done`. If you pass text to any of the creation commands which has multiple lines, everything after the first line break will become the note.
|
494
501
|
|
502
|
+
If a string passed to `now`, `later`, or `done` has a parenthetical at the end, the parenthetical will be removed from the title and its contents added as a note. So `doing now Working on @project1 (Adding some unit tests)` would create an entry titled "Working on @project1" with a note "Adding some unit tests." This is the equivalent of `doing now Working on @project1 -n "Adding some unit tests"`.
|
503
|
+
|
495
504
|
#### Displaying entries:
|
496
505
|
|
497
506
|
show - List all entries
|
@@ -517,6 +526,18 @@ If you have a use for it, you can use `-o csv` on the show or view commands to o
|
|
517
526
|
|
518
527
|
You can also show entries matching a search string with `doing grep` (synonym `doing search`). If you want to search with regular expressions or for an exact match, surround your search query with forward slashes, e.g. `doing search /project name/`. If you pass a search string without slashes, it's treated as a fuzzy search string, meaning matches can be found as long as the characters in the search string are in order and with no more than three other characters between each. By default searches are across all sections, but you can limit it to one with the `-s SECTION_NAME` flag. Searches can be displayed with the default template, or output as HTML, CSV, or JSON.
|
519
528
|
|
529
|
+
##### Modifying the last entry
|
530
|
+
|
531
|
+
If you want to make a change to the last entry added, use `doing last -e`. The `-e` flag opens the last entry (including note) in your editor, and when you close your editor, your doing file will be updated with any changes you made to the entry.
|
532
|
+
|
533
|
+
You can choose the last entry in a specific section by including the `-s` flag, so `doing last -s Later -e` would edit the most recent entry in the Later section.
|
534
|
+
|
535
|
+
You can also use text search or a tag filter to get an entry earlier than the most recent one. A tag search with `doing last --tag=project1 -e` will edit the last entry tagged `@project1`. Multiple tags can be combined with commas, and you can use `--bool` to specify whether the search is `AND` (matches all tags given), `OR` (matches any tag given), or `NOT` (matches none of the tags).
|
536
|
+
|
537
|
+
You can edit the last entry that matches a search string with `--search=QUERY`. `QUERY` can either be a raw string, or you can surround it with slashes to search by regex (`doing last --search="/project./" -e`). If the string is raw text, fuzzy matching will be used, so the characters must be in order but can be separated by up to three other characters.
|
538
|
+
|
539
|
+
Both `--tag` and `--search` can be constrained to a single section with `-s SECTION`.
|
540
|
+
|
520
541
|
#### Views
|
521
542
|
|
522
543
|
view - Display a user-created view
|
@@ -576,11 +597,14 @@ __Fish:__ See the file [`doing.fish`](https://github.com/ttscoff/doing/blob/mast
|
|
576
597
|
|
577
598
|
The LaunchBar action requires that `doing` be available in `/usr/local/bin/doing`. If it's not (because you're using RVM or similar), you'll need to symlink it there. Running the action with Return will show the latest 9 items from Currently, along with any time intervals recorded, and includes a submenu of Timers for each tag.
|
578
599
|
|
579
|
-
Pressing Spacebar and typing allows you to add a new entry to currently. You an also trigger a custom show command by typing "show [section/tag]" and hitting return.
|
600
|
+
Pressing Spacebar and typing allows you to add a new entry to currently. You an also trigger a custom show command by typing "show [section/tag]" and hitting return. Include any command line flags at the end of the string, and if you add text in parenthesis, it will be processed as a note on the entry.
|
580
601
|
|
581
602
|
Point of interest, the LaunchBar Action makes use of the `-o json` flag for outputting JSON to the action's script for parsing.
|
582
603
|
|
583
|
-
See <https://brettterpstra.com/projects/doing/> for the download
|
604
|
+
<!--GITHUB-->See <https://brettterpstra.com/projects/doing/> for the download.<!--END GITHUB-->
|
605
|
+
<!--JEKYLL
|
606
|
+
{% download 117 %}
|
607
|
+
-->
|
584
608
|
|
585
609
|
Evan Lovely has [created an Alfred workflow as well](http://www.evanlovely.com/blog/technology/alfred-for-terpstras-doing/).
|
586
610
|
|
@@ -621,7 +645,9 @@ Please try not to email me directly about GitHub projects.
|
|
621
645
|
|
622
646
|
Feel free to [poke around](http://github.com/ttscoff/doing/), I'll try to add more comments in the future (and retroactively).
|
623
647
|
|
624
|
-
|
648
|
+
<!--END README-->
|
649
|
+
|
650
|
+
PayPal link: [paypal.me/ttscoff](https://paypal.me/ttscoff)
|
625
651
|
|
626
652
|
## Changelog
|
627
653
|
|
data/bin/doing
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
$LOAD_PATH.unshift File.join(__dir__, '..', 'lib')
|
3
5
|
require 'gli'
|
4
6
|
require 'doing'
|
@@ -7,9 +9,9 @@ require 'pp'
|
|
7
9
|
|
8
10
|
def class_exists?(class_name)
|
9
11
|
klass = Module.const_get(class_name)
|
10
|
-
|
12
|
+
klass.is_a?(Class)
|
11
13
|
rescue NameError
|
12
|
-
|
14
|
+
false
|
13
15
|
end
|
14
16
|
|
15
17
|
if class_exists? 'Encoding'
|
@@ -17,358 +19,352 @@ if class_exists? 'Encoding'
|
|
17
19
|
Encoding.default_internal = Encoding::UTF_8 if Encoding.respond_to?('default_internal')
|
18
20
|
end
|
19
21
|
|
20
|
-
|
21
22
|
include GLI::App
|
22
23
|
version Doing::VERSION
|
23
24
|
|
24
25
|
wwid = WWID.new
|
25
|
-
if Dir.respond_to?('home')
|
26
|
-
|
27
|
-
else
|
28
|
-
|
29
|
-
end
|
26
|
+
wwid.user_home = if Dir.respond_to?('home')
|
27
|
+
Dir.home
|
28
|
+
else
|
29
|
+
File.expand_path('~')
|
30
|
+
end
|
30
31
|
wwid.configure
|
31
32
|
|
32
|
-
|
33
33
|
program_desc 'A CLI for a What Was I Doing system'
|
34
34
|
|
35
35
|
default_command :recent
|
36
36
|
# sort_help :manually
|
37
37
|
|
38
38
|
desc 'Output notes if included in the template'
|
39
|
-
default_value true
|
40
|
-
switch [:notes], :default_value => true, :negatable => true
|
39
|
+
switch [:notes], default_value: true, negatable: true
|
41
40
|
|
42
41
|
desc 'Send results report to STDOUT instead of STDERR'
|
43
|
-
default_value false
|
44
|
-
switch [:stdout], :default_value => false, :negatable => false
|
42
|
+
switch [:stdout], default_value: false, negatable: false
|
45
43
|
|
46
44
|
desc 'Exclude auto tags and default tags'
|
47
|
-
switch [
|
45
|
+
switch %i[x noauto], default_value: false
|
48
46
|
|
49
47
|
desc 'Use a specific configuration file'
|
50
|
-
default_value
|
51
|
-
flag [:config_file]
|
52
|
-
|
53
|
-
|
54
|
-
# desc 'Wrap notes at X chars (0 for no wrap)'
|
55
|
-
# flag [:w, :wrapwidth], :must_match => /^\d+$/, :type => Integer
|
48
|
+
flag [:config_file], default_value: wwid.config_file
|
56
49
|
|
57
50
|
desc 'Specify a different doing_file'
|
58
|
-
flag [
|
51
|
+
flag %i[f doing_file]
|
59
52
|
|
60
53
|
desc 'Add an entry'
|
61
|
-
arg_name '
|
54
|
+
arg_name 'ENTRY'
|
62
55
|
command [:now, :next] do |c|
|
63
56
|
c.desc 'Section'
|
64
|
-
c.arg_name '
|
65
|
-
c.flag [
|
57
|
+
c.arg_name 'NAME'
|
58
|
+
c.flag %i[s section], default_value: wwid.current_section
|
66
59
|
|
67
60
|
c.desc "Edit entry with #{ENV['EDITOR']}"
|
68
|
-
c.switch [
|
61
|
+
c.switch %i[e editor], negatable: false, default_value: false
|
69
62
|
|
70
63
|
c.desc 'Backdate start time [4pm|20m|2h|yesterday noon]'
|
71
|
-
c.
|
64
|
+
c.arg_name 'DATE_STRING'
|
65
|
+
c.flag %i[b back]
|
72
66
|
|
73
67
|
c.desc 'Timed entry, marks last entry in section as @done'
|
74
|
-
c.switch [
|
68
|
+
c.switch %i[f finish_last], negatable: false, default_value: false
|
75
69
|
|
76
70
|
c.desc 'Note'
|
77
|
-
c.arg_name '
|
78
|
-
c.flag [
|
71
|
+
c.arg_name 'TEXT'
|
72
|
+
c.flag %i[n note]
|
79
73
|
|
80
74
|
# c.desc "Edit entry with specified app"
|
81
75
|
# c.arg_name 'editor_app'
|
82
76
|
# # c.flag [:a, :app]
|
83
77
|
|
84
|
-
c.action do |
|
78
|
+
c.action do |_global_options, options, args|
|
85
79
|
if options[:back]
|
86
80
|
date = wwid.chronify(options[:back])
|
87
81
|
|
88
|
-
raise
|
82
|
+
raise 'Unable to parse date string' if date.nil?
|
89
83
|
else
|
90
84
|
date = Time.now
|
91
85
|
end
|
92
86
|
|
93
87
|
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
94
88
|
|
95
|
-
if options[:e] || (args.
|
96
|
-
raise
|
97
|
-
|
98
|
-
input
|
99
|
-
input
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
89
|
+
if options[:e] || (args.empty? && $stdin.stat.size.zero?)
|
90
|
+
raise 'No EDITOR variable defined in environment' if ENV['EDITOR'].nil?
|
91
|
+
|
92
|
+
input = ''
|
93
|
+
input += args.join(' ') unless args.empty?
|
94
|
+
input = wwid.fork_editor(input).strip
|
95
|
+
|
96
|
+
raise 'No content' if input.empty?
|
97
|
+
|
98
|
+
title, note = wwid.format_input(input)
|
99
|
+
note.push(options[:n]) if options[:n]
|
100
|
+
wwid.add_item(title.cap_first, section, { note: note, back: date, timed: options[:f] })
|
101
|
+
wwid.write(wwid.doing_file)
|
102
|
+
elsif args.length.positive?
|
103
|
+
title, note = wwid.format_input(args.join(' '))
|
104
|
+
note.push(options[:n]) if options[:n]
|
105
|
+
wwid.add_item(title.cap_first, section, { note: note, back: date, timed: options[:f] })
|
106
|
+
wwid.write(wwid.doing_file)
|
107
|
+
elsif $stdin.stat.size.positive?
|
108
|
+
title, note = wwid.format_input($stdin.read)
|
109
|
+
note.push(options[:n]) if options[:n]
|
110
|
+
wwid.add_item(title.cap_first, section, { note: note, back: date, timed: options[:f] })
|
111
|
+
wwid.write(wwid.doing_file)
|
108
112
|
else
|
109
|
-
|
110
|
-
title, note = wwid.format_input(args.join(" "))
|
111
|
-
note.push(options[:n]) if options[:n]
|
112
|
-
wwid.add_item(title.cap_first, section, {:note => note, :back => date, :timed => options[:f]})
|
113
|
-
wwid.write(wwid.doing_file)
|
114
|
-
elsif STDIN.stat.size > 0
|
115
|
-
title, note = wwid.format_input(STDIN.read)
|
116
|
-
note.push(options[:n]) if options[:n]
|
117
|
-
wwid.add_item(title.cap_first, section, {:note => note, :back => date, :timed => options[:f]})
|
118
|
-
wwid.write(wwid.doing_file)
|
119
|
-
else
|
120
|
-
raise "You must provide content when creating a new entry"
|
121
|
-
end
|
113
|
+
raise 'You must provide content when creating a new entry'
|
122
114
|
end
|
123
115
|
end
|
124
116
|
end
|
125
117
|
|
126
118
|
desc 'Add a note to the last entry'
|
127
|
-
long_desc %
|
119
|
+
long_desc %(
|
128
120
|
If -r is provided with no other arguments, the last note is removed. If new content is specified through arguments or STDIN, any previous note will be replaced with the new one.
|
129
121
|
|
130
122
|
Use -e to load the last entry in a text editor where you can append a note.
|
131
|
-
|
132
|
-
arg_name '
|
123
|
+
)
|
124
|
+
arg_name 'NOTE_TEXT'
|
133
125
|
command :note do |c|
|
134
126
|
c.desc 'Section'
|
135
|
-
c.arg_name '
|
136
|
-
c.flag [
|
127
|
+
c.arg_name 'NAME'
|
128
|
+
c.flag %i[s section], default_value: 'All'
|
137
129
|
|
138
130
|
c.desc "Edit entry with #{ENV['EDITOR']}"
|
139
|
-
c.switch [
|
131
|
+
c.switch %i[e editor], negatable: false, default_value: false
|
140
132
|
|
141
133
|
c.desc "Replace/Remove last entry's note (default append)"
|
142
|
-
c.switch [
|
134
|
+
c.switch %i[r remove], negatable: false, default_value: false
|
143
135
|
|
144
|
-
c.action do |
|
136
|
+
c.action do |_global_options, options, args|
|
145
137
|
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
146
138
|
|
147
|
-
if options[:e] || (args.
|
148
|
-
raise
|
139
|
+
if options[:e] || (args.empty? && $stdin.stat.size.zero? && !options[:r])
|
140
|
+
raise 'No EDITOR variable defined in environment' if ENV['EDITOR'].nil?
|
149
141
|
|
150
|
-
input = args.
|
142
|
+
input = !args.empty? ? args.join(' ') : ''
|
151
143
|
|
152
|
-
prev_input = wwid.last_note(section) ||
|
153
|
-
|
154
|
-
prev_input = prev_input.join("\n")
|
155
|
-
end
|
144
|
+
prev_input = wwid.last_note(section) || ''
|
145
|
+
prev_input = prev_input.join("\n") if prev_input.instance_of?(Array)
|
156
146
|
input = prev_input + input
|
157
147
|
|
158
|
-
input = wwid.fork_editor(input)
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
148
|
+
input = wwid.fork_editor(input).strip
|
149
|
+
raise 'No content, cancelled' unless input
|
150
|
+
|
151
|
+
_title, note = wwid.format_input(input)
|
152
|
+
|
153
|
+
raise 'No note content' unless note
|
154
|
+
|
155
|
+
wwid.note_last(section, note, replace: true)
|
156
|
+
elsif !args.empty?
|
157
|
+
title, note = wwid.format_input(args.join(' '))
|
158
|
+
note.insert(0, title)
|
159
|
+
wwid.note_last(section, note, replace: options[:r])
|
160
|
+
elsif $stdin.stat.size.positive?
|
161
|
+
title, note = wwid.format_input($stdin.read)
|
162
|
+
note.insert(0, title)
|
163
|
+
wwid.note_last(section, note, replace: options[:r])
|
164
|
+
elsif options[:r]
|
165
|
+
wwid.note_last(section, [], replace: true)
|
169
166
|
else
|
170
|
-
|
171
|
-
title, note = wwid.format_input(args.join(" "))
|
172
|
-
note.insert(0, title)
|
173
|
-
wwid.note_last(section, note, replace: options[:r])
|
174
|
-
elsif STDIN.stat.size > 0
|
175
|
-
title, note = wwid.format_input(STDIN.read)
|
176
|
-
note.insert(0, title)
|
177
|
-
wwid.note_last(section, note, replace: options[:r])
|
178
|
-
else
|
179
|
-
if options[:r]
|
180
|
-
wwid.note_last(section, [], replace: true)
|
181
|
-
else
|
182
|
-
raise "You must provide content when adding a note"
|
183
|
-
end
|
184
|
-
end
|
167
|
+
raise 'You must provide content when adding a note'
|
185
168
|
end
|
186
169
|
wwid.write(wwid.doing_file)
|
187
170
|
end
|
188
171
|
end
|
189
172
|
|
190
173
|
desc 'Finish any running @meanwhile tasks and optionally create a new one'
|
191
|
-
arg_name '
|
174
|
+
arg_name 'ENTRY'
|
192
175
|
command :meanwhile do |c|
|
193
176
|
c.desc 'Section'
|
194
|
-
c.arg_name '
|
195
|
-
c.flag [
|
177
|
+
c.arg_name 'NAME'
|
178
|
+
c.flag %i[s section], default_value: wwid.current_section
|
196
179
|
|
197
180
|
c.desc "Edit entry with #{ENV['EDITOR']}"
|
198
|
-
c.switch [
|
181
|
+
c.switch %i[e editor], negatable: false, default_value: false
|
199
182
|
|
200
|
-
c.desc
|
201
|
-
c.switch [
|
183
|
+
c.desc 'Archive previous @meanwhile entry'
|
184
|
+
c.switch %i[a archive], default_value: false
|
202
185
|
|
203
186
|
c.desc 'Backdate start date for new entry to date string [4pm|20m|2h|yesterday noon]'
|
204
|
-
c.
|
187
|
+
c.arg_name 'DATE_STRING'
|
188
|
+
c.flag %i[b back]
|
205
189
|
|
206
190
|
c.desc 'Note'
|
207
|
-
c.arg_name '
|
208
|
-
c.flag [
|
191
|
+
c.arg_name 'TEXT'
|
192
|
+
c.flag %i[n note]
|
209
193
|
|
210
|
-
c.action do |
|
194
|
+
c.action do |_global_options, options, args|
|
211
195
|
if options[:back]
|
212
196
|
date = wwid.chronify(options[:back])
|
213
197
|
|
214
|
-
raise
|
198
|
+
raise 'Unable to parse date string' if date.nil?
|
215
199
|
else
|
216
200
|
date = Time.now
|
217
201
|
end
|
218
202
|
|
219
203
|
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
220
|
-
input =
|
204
|
+
input = ''
|
221
205
|
|
222
206
|
if options[:e]
|
223
|
-
raise
|
224
|
-
|
225
|
-
input
|
207
|
+
raise 'No EDITOR variable defined in environment' if ENV['EDITOR'].nil?
|
208
|
+
|
209
|
+
input += args.join(' ') unless args.empty?
|
210
|
+
input = wwid.fork_editor(input).strip
|
211
|
+
elsif !args.empty?
|
212
|
+
input = args.join(' ')
|
213
|
+
elsif $stdin.stat.size.positive?
|
214
|
+
input = $stdin.read
|
215
|
+
end
|
216
|
+
|
217
|
+
if input && !input.empty?
|
218
|
+
input, note = wwid.format_input(input)
|
226
219
|
else
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
220
|
+
input = nil
|
221
|
+
note = []
|
222
|
+
end
|
223
|
+
|
224
|
+
if options[:n]
|
225
|
+
note.push(options[:n])
|
226
|
+
elsif note.empty?
|
227
|
+
note = nil
|
232
228
|
end
|
233
|
-
input = false unless input && input.length > 0
|
234
229
|
|
235
|
-
|
236
|
-
wwid.stop_start('meanwhile', {:new_item => input, :back => date, :section => section, :archive => options[:a], :note => note})
|
230
|
+
wwid.stop_start('meanwhile', { new_item: input, back: date, section: section, archive: options[:a], note: note })
|
237
231
|
wwid.write(wwid.doing_file)
|
238
232
|
end
|
239
233
|
end
|
240
234
|
|
241
|
-
desc 'Output HTML templates for customization'
|
242
|
-
long_desc %
|
243
|
-
Templates are printed to STDOUT for piping to a file.
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
c.action do |
|
251
|
-
|
252
|
-
|
235
|
+
desc 'Output HTML and CSS templates for customization'
|
236
|
+
long_desc %(
|
237
|
+
Templates are printed to STDOUT for piping to a file.
|
238
|
+
Save them and use them in the configuration file under html_template.
|
239
|
+
|
240
|
+
Example `doing template HAML > ~/styles/my_doing.haml`
|
241
|
+
)
|
242
|
+
arg_name 'TYPE', must_match: /^(html|haml|css)/i
|
243
|
+
command :template do |c|
|
244
|
+
c.action do |_global_options, options, args|
|
245
|
+
raise 'No type specified, use `doing template [HAML|CSS]`' if args.empty?
|
246
|
+
|
247
|
+
case options[:t]
|
248
|
+
when /html|haml/i
|
249
|
+
$stdout.puts wwid.haml_template
|
250
|
+
when /css/i
|
251
|
+
$stdout.puts wwid.css_template
|
253
252
|
else
|
254
|
-
|
255
|
-
$stdout.puts wwid.haml_template
|
256
|
-
elsif options[:t] =~ /css/i
|
257
|
-
$stdout.puts wwid.css_template
|
258
|
-
else
|
259
|
-
raise "Invalid type specified, use --type=[HAML|CSS]"
|
260
|
-
end
|
253
|
+
raise 'Invalid type specified, must be HAML or CSS'
|
261
254
|
end
|
262
255
|
end
|
263
256
|
end
|
264
257
|
|
265
|
-
|
266
258
|
desc 'Add an item to the Later section'
|
267
|
-
arg_name '
|
259
|
+
arg_name 'ENTRY'
|
268
260
|
command :later do |c|
|
269
261
|
c.desc "Edit entry with #{ENV['EDITOR']}"
|
270
|
-
c.switch [
|
262
|
+
c.switch %i[e editor], negatable: false, default_value: false
|
271
263
|
|
272
|
-
c.desc
|
273
|
-
c.arg_name '
|
274
|
-
c.flag [
|
264
|
+
c.desc 'Edit entry with specified app'
|
265
|
+
c.arg_name 'APP'
|
266
|
+
c.flag %i[a app]
|
275
267
|
|
276
268
|
c.desc 'Backdate start time to date string [4pm|20m|2h|yesterday noon]'
|
277
|
-
c.
|
269
|
+
c.arg_name 'DATE_STRING'
|
270
|
+
c.flag %i[b back]
|
278
271
|
|
279
272
|
c.desc 'Note'
|
280
|
-
c.arg_name '
|
281
|
-
c.flag [
|
273
|
+
c.arg_name 'TEXT'
|
274
|
+
c.flag %i[n note]
|
282
275
|
|
283
|
-
c.action do |
|
276
|
+
c.action do |_global_options, options, args|
|
284
277
|
if options[:back]
|
285
278
|
date = wwid.chronify(options[:back])
|
286
|
-
raise
|
279
|
+
raise 'Unable to parse date string' if date.nil?
|
287
280
|
else
|
288
281
|
date = Time.now
|
289
282
|
end
|
290
283
|
|
291
|
-
if options[:e] || (args.
|
292
|
-
raise
|
293
|
-
|
294
|
-
input
|
295
|
-
input = wwid.fork_editor(input)
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
284
|
+
if options[:e] || (args.empty? && $stdin.stat.size.zero?)
|
285
|
+
raise 'No EDITOR variable defined in environment' if ENV['EDITOR'].nil?
|
286
|
+
|
287
|
+
input = args.empty? ? '' : args.join(' ')
|
288
|
+
input = wwid.fork_editor(input).strip
|
289
|
+
raise 'No content' unless input && !input.empty?
|
290
|
+
|
291
|
+
title, note = wwid.format_input(input)
|
292
|
+
note.push(options[:n]) if options[:n]
|
293
|
+
wwid.add_item(title.cap_first, 'Later', { note: note, back: date })
|
294
|
+
wwid.write(wwid.doing_file)
|
295
|
+
elsif !args.empty?
|
296
|
+
title, note = wwid.format_input(args.join(' '))
|
297
|
+
note.push(options[:n]) if options[:n]
|
298
|
+
wwid.add_item(title.cap_first, 'Later', { note: note, back: date })
|
299
|
+
wwid.write(wwid.doing_file)
|
300
|
+
elsif $stdin.stat.size.positive?
|
301
|
+
title, note = wwid.format_input($stdin.read)
|
302
|
+
note.push(options[:n]) if options[:n]
|
303
|
+
wwid.add_item(title.cap_first, 'Later', { note: note, back: date })
|
304
|
+
wwid.write(wwid.doing_file)
|
304
305
|
else
|
305
|
-
|
306
|
-
title, note = wwid.format_input(args.join(" "))
|
307
|
-
note.push(options[:n]) if options[:n]
|
308
|
-
wwid.add_item(title.cap_first, "Later", {:note => note, :back => date})
|
309
|
-
wwid.write(wwid.doing_file)
|
310
|
-
elsif STDIN.stat.size > 0
|
311
|
-
title, note = wwid.format_input(STDIN.read)
|
312
|
-
note.push(options[:n]) if options[:n]
|
313
|
-
wwid.add_item(title.cap_first, "Later", {:note => note, :back => date})
|
314
|
-
wwid.write(wwid.doing_file)
|
315
|
-
else
|
316
|
-
raise "You must provide content when creating a new entry"
|
317
|
-
end
|
306
|
+
raise 'You must provide content when creating a new entry'
|
318
307
|
end
|
319
308
|
end
|
320
309
|
end
|
321
310
|
|
322
311
|
desc 'Add a completed item with @done(date). No argument finishes last entry.'
|
323
|
-
arg_name '
|
312
|
+
arg_name 'ENTRY'
|
324
313
|
command [:done, :did] do |c|
|
325
314
|
c.desc 'Remove @done tag'
|
326
|
-
c.switch [
|
315
|
+
c.switch %i[r remove], negatable: false, default_value: false
|
327
316
|
|
328
317
|
c.desc 'Include date'
|
329
|
-
c.switch [:date], :
|
318
|
+
c.switch [:date], negatable: true, default_value: true
|
330
319
|
|
331
320
|
c.desc 'Immediately archive the entry'
|
332
|
-
c.switch [
|
321
|
+
c.switch %i[a archive], negatable: false, default_value: false
|
333
322
|
|
334
|
-
c.desc
|
323
|
+
c.desc %(Set finish date to specific date/time (natural langauge parsed, e.g. --at=1:30pm).
|
324
|
+
If used, ignores --back. Used with --took, backdates start date)
|
325
|
+
c.arg_name 'DATE_STRING'
|
335
326
|
c.flag [:at]
|
336
327
|
|
337
328
|
c.desc 'Backdate start date by interval [4pm|20m|2h|yesterday noon]'
|
338
|
-
c.
|
329
|
+
c.arg_name 'DATE_STRING'
|
330
|
+
c.flag %i[b back]
|
339
331
|
|
340
|
-
c.desc
|
341
|
-
|
332
|
+
c.desc %(Set completion date to start date plus interval (XX[mhd] or HH:MM).
|
333
|
+
If used without the --back option, the start date will be moved back to allow
|
334
|
+
the completion date to be the current time.)
|
335
|
+
c.arg_name 'INTERVAL'
|
336
|
+
c.flag %i[t took]
|
342
337
|
|
343
338
|
c.desc 'Section'
|
344
|
-
c.
|
339
|
+
c.arg_name 'NAME'
|
340
|
+
c.flag %i[s section], default_value: wwid.current_section
|
345
341
|
|
346
342
|
c.desc "Edit entry with #{ENV['EDITOR']}"
|
347
|
-
c.switch [
|
343
|
+
c.switch %i[e editor], negatable: false, default_value: false
|
348
344
|
|
349
345
|
# c.desc "Edit entry with specified app"
|
350
346
|
# c.arg_name 'editor_app'
|
351
347
|
# # c.flag [:a, :app]
|
352
348
|
|
353
|
-
c.action do |
|
349
|
+
c.action do |_global_options, options, args|
|
354
350
|
took = 0
|
355
351
|
|
356
|
-
|
357
352
|
if options[:took]
|
358
353
|
took = wwid.chronify_qty(options[:took])
|
359
|
-
raise
|
354
|
+
raise 'Unable to parse date string for --took' if took.nil?
|
360
355
|
end
|
361
356
|
|
362
357
|
if options[:back]
|
363
358
|
date = wwid.chronify(options[:back])
|
364
|
-
raise
|
359
|
+
raise 'Unable to parse date string for --back' if date.nil?
|
365
360
|
else
|
366
361
|
date = options[:took] ? Time.now - took : Time.now
|
367
362
|
end
|
368
363
|
|
369
364
|
if options[:at]
|
370
365
|
finish_date = wwid.chronify(options[:at])
|
371
|
-
raise
|
366
|
+
raise 'Unable to parse date string for --at' if finish_date.nil?
|
367
|
+
|
372
368
|
date = options[:took] ? finish_date - took : finish_date
|
373
369
|
elsif options[:took]
|
374
370
|
finish_date = date + took
|
@@ -379,113 +375,147 @@ command [:done, :did] do |c|
|
|
379
375
|
end
|
380
376
|
|
381
377
|
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
382
|
-
donedate = options[:date] ? "(#{finish_date.strftime('%F %R')})" :
|
378
|
+
donedate = options[:date] ? "(#{finish_date.strftime('%F %R')})" : ''
|
383
379
|
|
384
380
|
if options[:e]
|
385
|
-
raise
|
386
|
-
|
387
|
-
input
|
388
|
-
input
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
elsif args.length == 0 && STDIN.stat.size == 0
|
381
|
+
raise 'No EDITOR variable defined in environment' if ENV['EDITOR'].nil?
|
382
|
+
|
383
|
+
input = ''
|
384
|
+
input += args.join(' ') unless args.empty?
|
385
|
+
input = wwid.fork_editor(input).strip
|
386
|
+
raise 'No content' unless input && !input.empty?
|
387
|
+
|
388
|
+
title, note = wwid.format_input(input)
|
389
|
+
title += " @done#{donedate}"
|
390
|
+
section = 'Archive' if options[:a]
|
391
|
+
wwid.add_item(title.cap_first, section.cap_first, { note: note, back: date })
|
392
|
+
wwid.write(wwid.doing_file)
|
393
|
+
elsif args.empty? && $stdin.stat.size.zero?
|
399
394
|
if options[:r]
|
400
|
-
wwid.tag_last({:
|
395
|
+
wwid.tag_last({ tags: ['done'], count: 1, section: section, remove: true })
|
401
396
|
else
|
402
|
-
wwid.tag_last({:
|
397
|
+
wwid.tag_last({ tags: ['done'], count: 1, section: section, archive: options[:a], back: finish_date,
|
398
|
+
date: options[:date] })
|
403
399
|
end
|
400
|
+
elsif !args.empty?
|
401
|
+
title, note = wwid.format_input(args.join(' '))
|
402
|
+
title.chomp!
|
403
|
+
title += " @done#{donedate}"
|
404
|
+
section = 'Archive' if options[:a]
|
405
|
+
wwid.add_item(title.cap_first, section.cap_first, { note: note, back: date })
|
406
|
+
wwid.write(wwid.doing_file)
|
407
|
+
elsif $stdin.stat.size.positive?
|
408
|
+
title, note = wwid.format_input($stdin.read)
|
409
|
+
title += " @done#{donedate}"
|
410
|
+
section = options[:a] ? 'Archive' : section
|
411
|
+
wwid.add_item(title.cap_first, section.cap_first, { note: note, back: date })
|
412
|
+
wwid.write(wwid.doing_file)
|
404
413
|
else
|
405
|
-
|
406
|
-
title, note = wwid.format_input(args.join(" "))
|
407
|
-
title.chomp!
|
408
|
-
title += " @done#{donedate}"
|
409
|
-
section = "Archive" if options[:a]
|
410
|
-
wwid.add_item(title.cap_first, section.cap_first, {:note => note, :back => date})
|
411
|
-
wwid.write(wwid.doing_file)
|
412
|
-
elsif STDIN.stat.size > 0
|
413
|
-
title, note = wwid.format_input(STDIN.read)
|
414
|
-
title += " @done#{donedate}"
|
415
|
-
section = options[:a] ? "Archive" : section
|
416
|
-
wwid.add_item(title.cap_first, section.cap_first, {:note => note, :back => date})
|
417
|
-
wwid.write(wwid.doing_file)
|
418
|
-
else
|
419
|
-
raise "You must provide content when creating a new entry"
|
420
|
-
end
|
414
|
+
raise 'You must provide content when creating a new entry'
|
421
415
|
end
|
422
416
|
end
|
423
417
|
end
|
424
418
|
|
425
419
|
desc 'End last X entries with no time tracked'
|
426
420
|
long_desc 'Adds @done tag without datestamp so no elapsed time is recorded. Alias for `doing finish --no-date`.'
|
427
|
-
arg_name '
|
421
|
+
arg_name 'COUNT'
|
428
422
|
command :cancel do |c|
|
429
423
|
c.desc 'Archive entries'
|
430
|
-
c.switch [
|
424
|
+
c.switch %i[a archive], negatable: false, default_value: false
|
431
425
|
|
432
426
|
c.desc 'Section'
|
433
|
-
c.
|
427
|
+
c.arg_name 'NAME'
|
428
|
+
c.flag %i[s section], default_value: wwid.current_section
|
429
|
+
|
430
|
+
c.desc 'Cancel the last X entries containing TAG. Separate multiple tags with comma (--tag=tag1,tag2)'
|
431
|
+
c.arg_name 'TAG'
|
432
|
+
c.flag [:tag]
|
434
433
|
|
435
|
-
c.
|
434
|
+
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
|
435
|
+
c.arg_name 'BOOLEAN'
|
436
|
+
c.flag [:bool], must_match: /^(and|or|not)$/i, default_value: 'AND'
|
436
437
|
|
438
|
+
c.action do |_global_options, options, args|
|
437
439
|
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
438
440
|
|
439
|
-
if
|
440
|
-
|
441
|
-
elsif args.length == 0 || args[0] =~ /\d+/
|
442
|
-
count = args[0] ? args[0].to_i : 1
|
443
|
-
wwid.tag_last({:tags => ["done"], :count => count, :section => section, :archive => options[:a], :sequential => false, :date => false })
|
441
|
+
if options[:tag].nil?
|
442
|
+
tags = []
|
444
443
|
else
|
445
|
-
|
444
|
+
tags = options[:tag].split(/ *, */).map { |t| t.strip.sub(/^@/, '') }
|
445
|
+
options[:bool] = options[:bool] =~ /^(and|or|not)$/i ? options[:bool].upcase : 'AND'
|
446
446
|
end
|
447
|
+
|
448
|
+
raise 'Only one argument allowed' if args.length > 1
|
449
|
+
|
450
|
+
raise 'Invalid argument (specify number of recent items to mark @done)' unless args.empty? || args[0] =~ /\d+/
|
451
|
+
|
452
|
+
count = args[0] ? args[0].to_i : 1
|
453
|
+
opts = {
|
454
|
+
archive: options[:a],
|
455
|
+
count: count,
|
456
|
+
date: false,
|
457
|
+
section: section,
|
458
|
+
sequential: false,
|
459
|
+
tag: tags,
|
460
|
+
tag_bool: options[:bool],
|
461
|
+
tags: ['done']
|
462
|
+
}
|
463
|
+
wwid.tag_last(opts)
|
447
464
|
end
|
448
465
|
end
|
449
466
|
|
450
467
|
desc 'Mark last X entries as @done'
|
451
468
|
long_desc 'Marks the last X entries with a @done tag and current date. Does not alter already completed entries.'
|
452
|
-
arg_name '
|
469
|
+
arg_name 'COUNT'
|
453
470
|
command :finish do |c|
|
454
471
|
c.desc 'Include date'
|
455
|
-
c.switch [:date], :
|
472
|
+
c.switch [:date], negatable: true, default_value: true
|
456
473
|
|
457
474
|
c.desc 'Backdate completed date to date string [4pm|20m|2h|yesterday noon]'
|
458
|
-
c.
|
475
|
+
c.arg_name 'DATE_STRING'
|
476
|
+
c.flag %i[b back]
|
459
477
|
|
460
478
|
c.desc 'Set the completed date to the start date plus XX[hmd]'
|
461
|
-
c.
|
479
|
+
c.arg_name 'INTERVAL'
|
480
|
+
c.flag %i[t took]
|
481
|
+
|
482
|
+
c.desc 'Finish the last X entries containing TAG.
|
483
|
+
Separate multiple tags with comma (--tag=tag1,tag2), combine with --bool'
|
484
|
+
c.arg_name 'TAG'
|
485
|
+
c.flag [:tag]
|
462
486
|
|
463
|
-
c.desc 'Finish the last X entries
|
464
|
-
c.
|
487
|
+
c.desc 'Finish the last X entries matching search filter, surround with slashes for regex (e.g. "/query.*/")'
|
488
|
+
c.arg_name 'QUERY'
|
489
|
+
c.flag [:search]
|
465
490
|
|
466
491
|
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
|
467
|
-
c.
|
492
|
+
c.arg_name 'BOOLEAN'
|
493
|
+
c.flag [:bool], must_match: /^(and|or|not)$/i, default_value: 'AND'
|
468
494
|
|
469
|
-
c.desc
|
470
|
-
|
495
|
+
c.desc %(Auto-generate finish dates from next entry's start time.
|
496
|
+
Automatically generate completion dates 1 minute before next start date.
|
497
|
+
--auto overrides the --date and --back parameters.)
|
498
|
+
c.switch [:auto], negatable: false, default_value: false
|
471
499
|
|
472
500
|
c.desc 'Archive entries'
|
473
|
-
c.switch [
|
501
|
+
c.switch %i[a archive], negatable: false, default_value: false
|
474
502
|
|
475
503
|
c.desc 'Section'
|
476
|
-
c.
|
477
|
-
|
478
|
-
c.action do |global_options,options,args|
|
504
|
+
c.arg_name 'NAME'
|
505
|
+
c.flag %i[s section], default_value: wwid.current_section
|
479
506
|
|
507
|
+
c.action do |_global_options, options, args|
|
480
508
|
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
481
509
|
|
482
510
|
unless options[:auto]
|
483
|
-
raise
|
511
|
+
raise '--back and --took cannot be used together' if options[:back] && options[:took]
|
512
|
+
|
513
|
+
raise '--search and --tag cannot be used together' if options[:search] && options[:tag]
|
484
514
|
|
485
515
|
if options[:back]
|
486
516
|
date = wwid.chronify(options[:back])
|
487
517
|
|
488
|
-
raise
|
518
|
+
raise 'Unable to parse date string' if date.nil?
|
489
519
|
elsif options[:took]
|
490
520
|
date = wwid.chronify_qty(options[:took])
|
491
521
|
else
|
@@ -493,192 +523,245 @@ command :finish do |c|
|
|
493
523
|
end
|
494
524
|
end
|
495
525
|
|
496
|
-
if options[:tag]
|
497
|
-
|
498
|
-
if options[:tag_bool] =~ /^(and|or|not)$/i
|
499
|
-
options[:tag_bool] = options[:tag_bool].upcase
|
500
|
-
else
|
501
|
-
options[:tag_bool] = 'AND'
|
502
|
-
end
|
503
|
-
end
|
504
|
-
|
505
|
-
if args.length > 1
|
506
|
-
raise "Only one argument allowed"
|
507
|
-
elsif args.length == 0 || args[0] =~ /\d+/
|
508
|
-
count = args[0] ? args[0].to_i : 1
|
509
|
-
wwid.tag_last({ tags: ["done"],count: count,section: section,archive: options[:a],sequential: options[:auto],date: options[:date], back: date, tag: options[:tag], tag_bool: options[:tag_bool] })
|
526
|
+
if options[:tag].nil?
|
527
|
+
tags = []
|
510
528
|
else
|
511
|
-
|
529
|
+
tags = options[:tag].split(/ *, */).map { |t| t.strip.sub(/^@/, '') }
|
530
|
+
options[:bool] = options[:bool] =~ /^(and|or|not)$/i ? options[:bool].upcase : 'AND'
|
512
531
|
end
|
532
|
+
|
533
|
+
raise 'Only one argument allowed' if args.length > 1
|
534
|
+
|
535
|
+
raise 'Invalid argument (specify number of recent items to mark @done)' unless args.length == 0 || args[0] =~ /\d+/
|
536
|
+
|
537
|
+
count = args[0] ? args[0].to_i : 1
|
538
|
+
opts = {
|
539
|
+
archive: options[:a],
|
540
|
+
back: date,
|
541
|
+
count: count,
|
542
|
+
date: options[:date],
|
543
|
+
search: options[:search],
|
544
|
+
section: section,
|
545
|
+
sequential: options[:auto],
|
546
|
+
tag: tags,
|
547
|
+
tag_bool: options[:bool],
|
548
|
+
tags: ['done']
|
549
|
+
}
|
550
|
+
wwid.tag_last(opts)
|
513
551
|
end
|
514
552
|
end
|
515
553
|
|
516
554
|
desc 'Repeat last entry as new entry'
|
517
|
-
arg_name 'section'
|
518
555
|
command [:again, :resume] do |c|
|
519
556
|
c.desc 'Section'
|
520
|
-
c.
|
557
|
+
c.arg_name 'NAME'
|
558
|
+
c.flag %i[s section], default_value: 'All'
|
521
559
|
|
522
|
-
c.desc '
|
523
|
-
c.arg_name '
|
524
|
-
c.flag [:
|
560
|
+
c.desc 'Add new entry to section (default: same section as repeated entry)'
|
561
|
+
c.arg_name 'SECTION_NAME'
|
562
|
+
c.flag [:in]
|
525
563
|
|
526
|
-
c.
|
527
|
-
|
564
|
+
c.desc 'Repeat last entry matching tags. Combine multiple tags with a comma.'
|
565
|
+
c.arg_name 'TAG'
|
566
|
+
c.flag [:tag]
|
567
|
+
|
568
|
+
c.desc 'Repeat last entry matching search. Surround with
|
569
|
+
slashes for regex (e.g. "/query/").'
|
570
|
+
c.arg_name 'QUERY'
|
571
|
+
c.flag [:search]
|
572
|
+
|
573
|
+
c.desc 'Boolean used to combine multiple tags'
|
574
|
+
c.arg_name 'BOOLEAN'
|
575
|
+
c.flag [:bool], must_match: /^(and|or|not)$/i, default_value: 'ALL'
|
576
|
+
|
577
|
+
c.desc 'Note'
|
578
|
+
c.arg_name 'TEXT'
|
579
|
+
c.flag %i[n note]
|
580
|
+
|
581
|
+
c.action do |_global_options, options, _args|
|
582
|
+
tags = options[:tag].nil? ? [] : options[:tag].split(/ *, */).map { |t| t.sub(/^@/, '').strip }
|
583
|
+
opts = {
|
584
|
+
in: options[:in],
|
585
|
+
note: options[:n],
|
586
|
+
search: options[:search],
|
587
|
+
section: options[:s],
|
588
|
+
tag: tags,
|
589
|
+
tag_bool: options[:bool]
|
590
|
+
}
|
591
|
+
wwid.restart_last(opts)
|
528
592
|
end
|
529
593
|
end
|
530
594
|
|
531
|
-
desc '
|
532
|
-
arg_name '
|
595
|
+
desc 'Add tag(s) to last entry'
|
596
|
+
arg_name 'TAG', :multiple
|
533
597
|
command :tag do |c|
|
534
598
|
c.desc 'Section'
|
535
|
-
c.
|
599
|
+
c.arg_name 'SECTION_NAME'
|
600
|
+
c.flag %i[s section], default_value: 'All'
|
536
601
|
|
537
602
|
c.desc 'How many recent entries to tag (0 for all)'
|
538
|
-
c.
|
603
|
+
c.arg_name 'COUNT'
|
604
|
+
c.flag %i[c count], default_value: 1
|
539
605
|
|
540
606
|
c.desc 'Include current date/time with tag'
|
541
|
-
c.switch [
|
607
|
+
c.switch %i[d date], negatable: false, default_value: false
|
542
608
|
|
543
609
|
c.desc 'Remove given tag(s)'
|
544
|
-
c.switch [
|
610
|
+
c.switch %i[r remove], negatable: false, default_value: false
|
545
611
|
|
546
612
|
c.desc 'Autotag entries based on autotag configuration in ~/.doingrc'
|
547
|
-
c.switch [
|
613
|
+
c.switch %i[a autotag], negatable: false, default_value: false
|
548
614
|
|
549
|
-
c.action do |
|
550
|
-
if args.
|
551
|
-
raise "You must specify at least one tag"
|
552
|
-
else
|
553
|
-
|
554
|
-
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
615
|
+
c.action do |_global_options, options, args|
|
616
|
+
raise 'You must specify at least one tag' if args.empty? && !options[:a]
|
555
617
|
|
556
|
-
|
557
|
-
if args.join("") =~ /,/
|
558
|
-
tags = args.join("").split(/,/)
|
559
|
-
else
|
560
|
-
tags = args.join(" ").split(" ") # in case tags are quoted as one arg
|
561
|
-
end
|
618
|
+
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
562
619
|
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
620
|
+
if options[:a]
|
621
|
+
tags = []
|
622
|
+
else
|
623
|
+
tags = if args.join('') =~ /,/
|
624
|
+
args.join('').split(/,/)
|
625
|
+
else
|
626
|
+
args.join(' ').split(' ') # in case tags are quoted as one arg
|
627
|
+
end
|
567
628
|
|
568
|
-
|
629
|
+
tags.map! { |tag| tag.sub(/^@/, '').strip }
|
630
|
+
end
|
569
631
|
|
570
|
-
|
571
|
-
section_q = section == 'All' ? "" : " in section #{section}"
|
632
|
+
count = options[:c].to_i
|
572
633
|
|
573
|
-
|
574
|
-
|
575
|
-
elsif options[:r]
|
576
|
-
question = "Are you sure you want to remove #{tags.join(" and ")} from all records#{section_q}"
|
577
|
-
else
|
578
|
-
question = "Are you sure you want to add #{tags.join(" and ")} to all records#{section_q}"
|
579
|
-
end
|
634
|
+
if count.zero?
|
635
|
+
section_q = section == 'All' ? '' : " in section #{section}"
|
580
636
|
|
581
|
-
|
637
|
+
question = if options[:a]
|
638
|
+
"Are you sure you want to autotag all records#{section_q}"
|
639
|
+
elsif options[:r]
|
640
|
+
"Are you sure you want to remove #{tags.join(' and ')} from all records#{section_q}"
|
641
|
+
else
|
642
|
+
"Are you sure you want to add #{tags.join(' and ')} to all records#{section_q}"
|
643
|
+
end
|
582
644
|
|
583
|
-
|
584
|
-
raise "Cancelled"
|
585
|
-
end
|
586
|
-
end
|
645
|
+
res = wwid.yn(question, default_response: false)
|
587
646
|
|
588
|
-
|
647
|
+
raise 'Cancelled' unless res
|
589
648
|
end
|
649
|
+
opts = {
|
650
|
+
autotag: options[:a],
|
651
|
+
count: count,
|
652
|
+
date: options[:date],
|
653
|
+
remove: options[:r],
|
654
|
+
section: section,
|
655
|
+
tags: tags
|
656
|
+
}
|
657
|
+
wwid.tag_last(opts)
|
590
658
|
end
|
591
659
|
end
|
592
660
|
|
593
661
|
desc 'Mark last entry as highlighted'
|
594
662
|
command [:mark, :flag] do |c|
|
595
663
|
c.desc 'Section'
|
596
|
-
c.
|
664
|
+
c.arg_name 'NAME'
|
665
|
+
c.flag %i[s section], default_value: wwid.current_section
|
597
666
|
|
598
667
|
c.desc 'Remove mark'
|
599
|
-
c.switch [
|
600
|
-
|
668
|
+
c.switch %i[r remove], negatable: false, default_value: false
|
601
669
|
|
602
|
-
c.action do |
|
603
|
-
mark = wwid.config['marker_tag'] ||
|
604
|
-
wwid.tag_last({:
|
670
|
+
c.action do |_global_options, options, _args|
|
671
|
+
mark = wwid.config['marker_tag'] || 'flagged'
|
672
|
+
wwid.tag_last({ tags: [mark], section: options[:s], remove: options[:r] })
|
605
673
|
end
|
606
674
|
end
|
607
675
|
|
608
676
|
desc 'List all entries'
|
609
|
-
long_desc
|
610
|
-
|
677
|
+
long_desc %(
|
678
|
+
The argument can be a section name, @tag(s) or both.
|
679
|
+
"pick" or "choose" as an argument will offer a section menu.
|
680
|
+
)
|
681
|
+
arg_name '[SECTION|@TAGS]'
|
611
682
|
command :show do |c|
|
683
|
+
c.desc 'Tag filter, combine multiple tags with a comma. Added for compatibility with other commands.'
|
684
|
+
c.arg_name 'TAG'
|
685
|
+
c.flag [:tag]
|
686
|
+
|
612
687
|
c.desc 'Tag boolean (AND,OR,NONE)'
|
613
|
-
c.
|
688
|
+
c.arg_name 'BOOLEAN'
|
689
|
+
c.flag %i[b bool], must_match: /^(and|or|not)$/i, default_value: 'OR'
|
614
690
|
|
615
691
|
c.desc 'Max count to show'
|
616
|
-
c.
|
692
|
+
c.arg_name 'MAX'
|
693
|
+
c.flag %i[c count], default_value: 0
|
617
694
|
|
618
695
|
c.desc 'Age (oldest/newest)'
|
619
|
-
c.
|
696
|
+
c.arg_name 'AGE'
|
697
|
+
c.flag %i[a age], default_value: 'newest'
|
620
698
|
|
621
699
|
c.desc 'Sort order (asc/desc)'
|
622
|
-
c.
|
700
|
+
c.arg_name 'ORDER'
|
701
|
+
c.flag %i[s sort], must_match: /^(a|d)/i, default_value: 'ASC'
|
623
702
|
|
624
|
-
c.desc %
|
703
|
+
c.desc %(
|
625
704
|
Date range to show, or a single day to filter date on.
|
626
705
|
Date range argument should be quoted. Date specifications can be natural language.
|
627
706
|
To specify a range, use "to" or "through": `doing show --from "monday to friday"`
|
628
|
-
|
629
|
-
c.
|
707
|
+
)
|
708
|
+
c.arg_name 'DATE_OR_RANGE'
|
709
|
+
c.flag %i[f from]
|
630
710
|
|
631
711
|
c.desc 'Show time intervals on @done tasks'
|
632
|
-
c.switch [
|
712
|
+
c.switch %i[t times], default_value: true
|
633
713
|
|
634
714
|
c.desc 'Show intervals with totals at the end of output'
|
635
|
-
c.switch [:totals], :
|
715
|
+
c.switch [:totals], default_value: false, negatable: true
|
636
716
|
|
637
717
|
c.desc 'Sort tags by (name|time)'
|
638
718
|
default = 'time'
|
639
|
-
if wwid.config.
|
640
|
-
|
641
|
-
|
642
|
-
c.flag [:tag_sort], :default_value => default
|
719
|
+
default = wwid.config['tag_sort'] if wwid.config.key?('tag_sort')
|
720
|
+
c.arg_name 'KEY'
|
721
|
+
c.flag [:tag_sort], must_match: /^(name|time)/i, default_value: default
|
643
722
|
|
644
723
|
c.desc 'Only show items with recorded time intervals'
|
645
|
-
c.switch [:only_timed], :
|
646
|
-
|
647
|
-
c.desc 'Output to export format (csv|html|json)'
|
648
|
-
c.flag [:o, :output]
|
649
|
-
c.action do |global_options,options,args|
|
724
|
+
c.switch [:only_timed], default_value: false, negatable: false
|
650
725
|
|
726
|
+
c.desc 'Output to export format (csv|html|json|template|timeline)'
|
727
|
+
c.arg_name 'FORMAT'
|
728
|
+
c.flag %i[o output], must_match: /^(template|html|csv|json|timeline)$/i
|
729
|
+
c.action do |_global_options, options, args|
|
651
730
|
tag_filter = false
|
652
731
|
tags = []
|
653
|
-
if args.length
|
654
|
-
|
655
|
-
|
732
|
+
if args.length.positive?
|
733
|
+
case args[0]
|
734
|
+
when /^all$/i
|
735
|
+
section = 'All'
|
656
736
|
args.shift
|
657
|
-
|
737
|
+
when /^(choose|pick)$/i
|
658
738
|
section = wwid.choose_section
|
659
739
|
args.shift
|
660
|
-
|
661
|
-
section =
|
740
|
+
when /^@/
|
741
|
+
section = 'All'
|
662
742
|
else
|
663
743
|
section = wwid.guess_section(args[0])
|
664
744
|
raise "No such section: #{args[0]}" unless section
|
745
|
+
|
665
746
|
args.shift
|
666
747
|
end
|
667
|
-
if args.length
|
668
|
-
args.each
|
748
|
+
if args.length.positive?
|
749
|
+
args.each do |arg|
|
669
750
|
if arg =~ /,/
|
670
|
-
arg.split(/,/).each
|
671
|
-
tags.push(tag.strip.sub(/^@/,''))
|
672
|
-
|
751
|
+
arg.split(/,/).each do |tag|
|
752
|
+
tags.push(tag.strip.sub(/^@/, ''))
|
753
|
+
end
|
673
754
|
else
|
674
|
-
tags.push(arg.strip.sub(/^@/,''))
|
755
|
+
tags.push(arg.strip.sub(/^@/, ''))
|
675
756
|
end
|
676
|
-
|
757
|
+
end
|
677
758
|
end
|
678
759
|
else
|
679
760
|
section = wwid.current_section
|
680
761
|
end
|
681
762
|
|
763
|
+
tags.concat(options[:tag].split(/ *, */).map { |t| t.sub(/^@/, '').strip }) if options[:tag]
|
764
|
+
|
682
765
|
unless tags.empty?
|
683
766
|
tag_filter = {
|
684
767
|
'tags' => tags,
|
@@ -696,96 +779,127 @@ command :show do |c|
|
|
696
779
|
start = wwid.chronify(date_string)
|
697
780
|
finish = false
|
698
781
|
end
|
699
|
-
exit_now!
|
700
|
-
dates = [start,finish]
|
782
|
+
exit_now! 'Unrecognized date string' unless start
|
783
|
+
dates = [start, finish]
|
701
784
|
end
|
702
785
|
|
703
786
|
options[:t] = true if options[:totals]
|
704
787
|
|
705
|
-
|
706
|
-
|
707
|
-
puts wwid.list_section({:section => section, :date_filter => dates, :count => options[:c].to_i, :tag_filter => tag_filter, :age => options[:a], :order => options[:s], :output => options[:output], :times => options[:t], :totals => options[:totals], :sort_tags => options[:sort_tags], :highlight => true, :only_timed => options[:only_timed]})
|
788
|
+
tags_color = wwid.config.key?('tags_color') ? wwid.config['tags_color'] : nil
|
708
789
|
|
790
|
+
options[:sort_tags] = options[:tag_sort] =~ /^n/i
|
791
|
+
opts = {
|
792
|
+
age: options[:a],
|
793
|
+
count: options[:c].to_i,
|
794
|
+
date_filter: dates,
|
795
|
+
highlight: true,
|
796
|
+
only_timed: options[:only_timed],
|
797
|
+
order: options[:s],
|
798
|
+
output: options[:output],
|
799
|
+
section: section,
|
800
|
+
sort_tags: options[:sort_tags],
|
801
|
+
tag_filter: tag_filter,
|
802
|
+
tags_color: tags_color,
|
803
|
+
times: options[:t],
|
804
|
+
totals: options[:totals]
|
805
|
+
}
|
806
|
+
puts wwid.list_section(opts)
|
709
807
|
end
|
710
808
|
end
|
711
809
|
|
712
810
|
desc 'Search for entries'
|
713
|
-
long_desc
|
714
|
-
Search all sections (or limit to a single section) for entries matching text or regular expression. Normal strings are fuzzy matched.
|
811
|
+
long_desc <<~'EODESC'
|
812
|
+
Search all sections (or limit to a single section) for entries matching text or regular expression. Normal strings are fuzzy matched.
|
715
813
|
|
716
|
-
To search with regular expressions, single quote the string and surround with slashes: `doing search '/\bm.*?x\b/'`
|
814
|
+
To search with regular expressions, single quote the string and surround with slashes: `doing search '/\bm.*?x\b/'`
|
717
815
|
EODESC
|
718
816
|
|
719
|
-
arg_name '
|
817
|
+
arg_name 'SEARCH_PATTERN'
|
720
818
|
command [:grep, :search] do |c|
|
721
819
|
c.desc 'Section'
|
722
|
-
c.
|
820
|
+
c.arg_name 'NAME'
|
821
|
+
c.flag %i[s section], default_value: 'All'
|
723
822
|
|
724
|
-
c.desc 'Output to export format (csv|html|json)'
|
725
|
-
c.
|
823
|
+
c.desc 'Output to export format (csv|html|json|template|timeline)'
|
824
|
+
c.arg_name 'FORMAT'
|
825
|
+
c.flag %i[o output], must_match: /^(template|html|csv|json|timeline)$/i
|
726
826
|
|
727
827
|
c.desc 'Show time intervals on @done tasks'
|
728
|
-
c.switch [
|
828
|
+
c.switch %i[t times], default_value: true
|
729
829
|
|
730
830
|
c.desc 'Show intervals with totals at the end of output'
|
731
|
-
c.switch [:totals], :
|
831
|
+
c.switch [:totals], default_value: false, negatable: true
|
732
832
|
|
733
833
|
c.desc 'Sort tags by (name|time)'
|
734
834
|
default = 'time'
|
735
|
-
if wwid.config.
|
736
|
-
|
737
|
-
|
738
|
-
c.flag [:tag_sort], :default_value => default
|
835
|
+
default = wwid.config['tag_sort'] if wwid.config.key?('tag_sort')
|
836
|
+
c.arg_name 'KEY'
|
837
|
+
c.flag [:tag_sort], must_match: /^(name|time)$/i, default_value: default
|
739
838
|
|
740
839
|
c.desc 'Only show items with recorded time intervals'
|
741
|
-
c.switch [:only_timed], :
|
840
|
+
c.switch [:only_timed], default_value: false, negatable: false
|
742
841
|
|
743
|
-
c.action do |
|
842
|
+
c.action do |_global_options, options, args|
|
843
|
+
tags_color = wwid.config.key?('tags_color') ? wwid.config['tags_color'] : nil
|
744
844
|
|
745
845
|
section = wwid.guess_section(options[:s]) if options[:s]
|
746
846
|
|
747
847
|
options[:t] = true if options[:totals]
|
748
848
|
options[:sort_tags] = options[:tag_sort] =~ /^n/i
|
749
849
|
|
750
|
-
|
850
|
+
opts = {
|
851
|
+
highlight: true,
|
852
|
+
only_timed: options[:only_timed],
|
853
|
+
output: options[:output],
|
854
|
+
search: args.join(' '),
|
855
|
+
section: section,
|
856
|
+
sort_tags: options[:sort_tags],
|
857
|
+
tags_color: tags_color,
|
858
|
+
times: options[:t],
|
859
|
+
totals: options[:totals]
|
860
|
+
}
|
751
861
|
|
862
|
+
puts wwid.list_section(opts)
|
752
863
|
end
|
753
864
|
end
|
754
865
|
|
755
866
|
desc 'List recent entries'
|
756
867
|
default_value 10
|
757
|
-
arg_name '
|
868
|
+
arg_name 'COUNT'
|
758
869
|
command :recent do |c|
|
759
870
|
c.desc 'Section'
|
760
|
-
c.
|
871
|
+
c.arg_name 'NAME'
|
872
|
+
c.flag %i[s section], default_value: 'All'
|
761
873
|
|
762
874
|
c.desc 'Show time intervals on @done tasks'
|
763
|
-
c.switch [
|
875
|
+
c.switch %i[t times], default_value: true
|
764
876
|
|
765
877
|
c.desc 'Show intervals with totals at the end of output'
|
766
|
-
c.switch [:totals], :
|
878
|
+
c.switch [:totals], default_value: false, negatable: true
|
767
879
|
|
768
880
|
c.desc 'Sort tags by (name|time)'
|
769
881
|
default = 'time'
|
770
|
-
if wwid.config.
|
771
|
-
|
772
|
-
|
773
|
-
c.flag [:tag_sort], :default_value => default
|
774
|
-
|
775
|
-
c.action do |global_options,options,args|
|
882
|
+
default = wwid.config['tag_sort'] if wwid.config.key?('tag_sort')
|
883
|
+
c.arg_name 'KEY'
|
884
|
+
c.flag [:tag_sort], must_match: /^(name|time)$/i, default_value: default
|
776
885
|
|
886
|
+
c.action do |global_options, options, args|
|
777
887
|
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
778
888
|
|
779
889
|
unless global_options[:version]
|
780
|
-
|
781
|
-
count = args[0].to_i
|
782
|
-
else
|
783
|
-
count = 10
|
784
|
-
end
|
890
|
+
count = args.empty? ? 10 : args[0].to_i
|
785
891
|
options[:t] = true if options[:totals]
|
786
892
|
options[:sort_tags] = options[:tag_sort] =~ /^n/i
|
893
|
+
tags_color = wwid.config.key?('tags_color') ? wwid.config['tags_color'] : nil
|
894
|
+
|
895
|
+
opts = {
|
896
|
+
sort_tags: options[:sort_tags],
|
897
|
+
tags_color: tags_color,
|
898
|
+
times: options[:t],
|
899
|
+
totals: options[:totals]
|
900
|
+
}
|
787
901
|
|
788
|
-
puts wwid.recent(count,section.cap_first,
|
902
|
+
puts wwid.recent(count, section.cap_first, opts)
|
789
903
|
|
790
904
|
end
|
791
905
|
end
|
@@ -794,62 +908,64 @@ end
|
|
794
908
|
desc 'List entries from today'
|
795
909
|
command :today do |c|
|
796
910
|
c.desc 'Specify a section'
|
797
|
-
c.arg_name '
|
798
|
-
c.flag [
|
911
|
+
c.arg_name 'NAME'
|
912
|
+
c.flag %i[s section], default_value: 'All'
|
799
913
|
|
800
914
|
c.desc 'Show time intervals on @done tasks'
|
801
|
-
c.switch [
|
915
|
+
c.switch %i[t times], default_value: true
|
802
916
|
|
803
917
|
c.desc 'Show time totals at the end of output'
|
804
|
-
c.switch [:totals], :
|
918
|
+
c.switch [:totals], default_value: false, negatable: true
|
805
919
|
|
806
920
|
c.desc 'Sort tags by (name|time)'
|
807
921
|
default = 'time'
|
808
|
-
if wwid.config.
|
809
|
-
|
810
|
-
|
811
|
-
c.flag [:tag_sort], :default_value => default
|
812
|
-
|
813
|
-
c.desc 'Output to export format (csv|html|json)'
|
814
|
-
c.flag [:o, :output]
|
922
|
+
default = wwid.config['tag_sort'] if wwid.config.key?('tag_sort')
|
923
|
+
c.arg_name 'KEY'
|
924
|
+
c.flag [:tag_sort], must_match: /^(name|time)$/i, default_value: default
|
815
925
|
|
816
|
-
c.
|
926
|
+
c.desc 'Output to export format (csv|html|json|template|timeline)'
|
927
|
+
c.arg_name 'FORMAT'
|
928
|
+
c.flag %i[o output], must_match: /^(template|html|csv|json|timeline)$/i
|
817
929
|
|
930
|
+
c.action do |_global_options, options, _args|
|
818
931
|
options[:t] = true if options[:totals]
|
819
932
|
options[:sort_tags] = options[:tag_sort] =~ /^n/i
|
820
933
|
|
821
|
-
puts wwid.today(options[:t],options[:output],
|
822
|
-
|
934
|
+
puts wwid.today(options[:t], options[:output],
|
935
|
+
{ totals: options[:totals], section: options[:s], sort_tags: options[:sort_tags] }).chomp
|
823
936
|
end
|
824
937
|
end
|
825
938
|
|
826
939
|
desc 'List entries for a date'
|
827
|
-
long_desc
|
828
|
-
|
940
|
+
long_desc %(Date argument can be natural language. "thursday" would be interpreted as "last thursday,"
|
941
|
+
and "2d" would be interpreted as "two days ago." If you use "to" or "through" between two dates,
|
942
|
+
it will create a range.)
|
943
|
+
arg_name 'DATE_STRING'
|
829
944
|
command :on do |c|
|
830
945
|
c.desc 'Section'
|
831
|
-
c.arg_name '
|
832
|
-
c.flag [
|
946
|
+
c.arg_name 'NAME'
|
947
|
+
c.flag %i[s section], default_value: 'All'
|
833
948
|
|
834
949
|
c.desc 'Show time intervals on @done tasks'
|
835
|
-
c.switch [
|
950
|
+
c.switch %i[t times], default_value: true
|
836
951
|
|
837
952
|
c.desc 'Show time totals at the end of output'
|
838
|
-
c.switch [:totals], :
|
953
|
+
c.switch [:totals], default_value: false, negatable: true
|
839
954
|
|
840
955
|
c.desc 'Sort tags by (name|time)'
|
841
956
|
default = 'time'
|
842
|
-
if wwid.config.
|
843
|
-
|
844
|
-
|
845
|
-
c.flag [:tag_sort], :default_value => default
|
957
|
+
default = wwid.config['tag_sort'] if wwid.config.key?('tag_sort')
|
958
|
+
c.arg_name 'KEY'
|
959
|
+
c.flag [:tag_sort], must_match: /^(name|time)$/i, default_value: default
|
846
960
|
|
847
|
-
c.desc 'Output to export format (csv|html|json)'
|
848
|
-
c.
|
961
|
+
c.desc 'Output to export format (csv|html|json|template|timeline)'
|
962
|
+
c.arg_name 'FORMAT'
|
963
|
+
c.flag %i[o output], must_match: /^(template|html|csv|json|timeline)$/i
|
849
964
|
|
850
|
-
c.action do |
|
965
|
+
c.action do |_global_options, options, args|
|
966
|
+
exit_now! 'Missing date argument' if args.empty?
|
851
967
|
|
852
|
-
date_string = args.join(
|
968
|
+
date_string = args.join(' ')
|
853
969
|
|
854
970
|
if date_string =~ / (to|through|thru) /
|
855
971
|
dates = date_string.split(/ (to|through|thru) /)
|
@@ -860,7 +976,7 @@ command :on do |c|
|
|
860
976
|
finish = false
|
861
977
|
end
|
862
978
|
|
863
|
-
exit_now!
|
979
|
+
exit_now! 'Unrecognized date string' unless start
|
864
980
|
|
865
981
|
message = "Date interpreted as #{start}"
|
866
982
|
message += " to #{finish}" if finish
|
@@ -869,56 +985,86 @@ command :on do |c|
|
|
869
985
|
options[:t] = true if options[:totals]
|
870
986
|
options[:sort_tags] = options[:tag_sort] =~ /^n/i
|
871
987
|
|
872
|
-
puts wwid.list_date([start, finish], options[:s], options[:t], options[:output],
|
873
|
-
|
988
|
+
puts wwid.list_date([start, finish], options[:s], options[:t], options[:output],
|
989
|
+
{ totals: options[:totals], sort_tags: options[:sort_tags] }).chomp
|
874
990
|
end
|
875
991
|
end
|
876
992
|
|
877
993
|
desc 'List entries from yesterday'
|
878
994
|
command :yesterday do |c|
|
879
995
|
c.desc 'Specify a section'
|
880
|
-
c.arg_name '
|
881
|
-
c.flag [
|
996
|
+
c.arg_name 'NAME'
|
997
|
+
c.flag %i[s section], default_value: 'All'
|
882
998
|
|
883
|
-
c.desc 'Output to export format (csv|html|json)'
|
884
|
-
c.
|
999
|
+
c.desc 'Output to export format (csv|html|json|template|timeline)'
|
1000
|
+
c.arg_name 'FORMAT'
|
1001
|
+
c.flag %i[o output], must_match: /^(template|html|csv|json|timeline)$/i
|
885
1002
|
|
886
1003
|
c.desc 'Show time intervals on @done tasks'
|
887
|
-
c.switch [
|
1004
|
+
c.switch %i[t times], default_value: true
|
888
1005
|
|
889
1006
|
c.desc 'Show time totals at the end of output'
|
890
|
-
c.switch [:totals], :
|
1007
|
+
c.switch [:totals], default_value: false, negatable: true
|
891
1008
|
|
892
1009
|
c.desc 'Sort tags by (name|time)'
|
893
1010
|
default = 'time'
|
894
|
-
if wwid.config.
|
895
|
-
|
896
|
-
|
897
|
-
c.flag [:tag_sort], :default_value => default
|
1011
|
+
default = wwid.config['tag_sort'] if wwid.config.key?('tag_sort')
|
1012
|
+
c.arg_name 'KEY'
|
1013
|
+
c.flag [:tag_sort], must_match: /^(name|time)$/i, default_value: default
|
898
1014
|
|
899
|
-
c.action do |
|
1015
|
+
c.action do |_global_options, options, _args|
|
900
1016
|
options[:sort_tags] = options[:tag_sort] =~ /^n/i
|
901
|
-
puts wwid.yesterday(options[:s],options[:t],options[:o],
|
902
|
-
|
1017
|
+
puts wwid.yesterday(options[:s], options[:t], options[:o],
|
1018
|
+
{ totals: options[:totals], sort_tags: options[:sort_tags] }).chomp
|
903
1019
|
end
|
904
1020
|
end
|
905
1021
|
|
906
|
-
desc 'Show the last entry'
|
1022
|
+
desc 'Show the last entry, optionally edit'
|
907
1023
|
command :last do |c|
|
908
1024
|
c.desc 'Specify a section'
|
909
|
-
c.
|
1025
|
+
c.arg_name 'NAME'
|
1026
|
+
c.flag %i[s section], default_value: 'All'
|
910
1027
|
|
911
|
-
c.
|
912
|
-
|
1028
|
+
c.desc "Edit entry with #{ENV['EDITOR']}"
|
1029
|
+
c.switch %i[e editor], negatable: false, default_value: false
|
1030
|
+
|
1031
|
+
c.desc 'Tag filter, combine multiple tags with a comma.'
|
1032
|
+
c.arg_name 'TAG'
|
1033
|
+
c.flag [:tag]
|
1034
|
+
|
1035
|
+
c.desc 'Tag boolean'
|
1036
|
+
c.arg_name 'BOOLEAN'
|
1037
|
+
c.flag [:bool], must_match: /(and|or|not)/i, default_value: 'AND'
|
1038
|
+
|
1039
|
+
c.desc 'Search filter, surround with slashes for regex (/query/)'
|
1040
|
+
c.arg_name 'QUERY'
|
1041
|
+
c.flag [:search]
|
1042
|
+
|
1043
|
+
c.action do |_global_options, options, _args|
|
1044
|
+
raise '--tag and --search cannot be used together' if options[:tag] && options[:search]
|
1045
|
+
|
1046
|
+
if options[:tag].nil?
|
1047
|
+
tags = []
|
1048
|
+
else
|
1049
|
+
tags = options[:tag].split(/ *, */).map { |t| t.strip.sub(/^@/, '') }
|
1050
|
+
options[:bool] = options[:bool] =~ /^(and|or|not)$/i ? options[:bool].upcase : 'AND'
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
if options[:e]
|
1054
|
+
wwid.edit_last(section: options[:s], options: { search: options[:search], tag: tags, tag_bool: options[:bool] })
|
1055
|
+
else
|
1056
|
+
puts wwid.last(times: true, section: options[:s],
|
1057
|
+
options: { search: options[:search], tag: tags, tag_bool: options[:bool] }).strip
|
1058
|
+
end
|
913
1059
|
end
|
914
1060
|
end
|
915
1061
|
|
916
1062
|
desc 'List sections'
|
917
1063
|
command :sections do |c|
|
918
1064
|
c.desc 'List in single column'
|
919
|
-
c.switch [
|
1065
|
+
c.switch %i[c column], default_value: false
|
920
1066
|
|
921
|
-
c.action do |
|
1067
|
+
c.action do |_global_options, options, _args|
|
922
1068
|
joiner = options[:c] ? "\n" : "\t"
|
923
1069
|
print wwid.sections.join(joiner)
|
924
1070
|
end
|
@@ -926,124 +1072,145 @@ end
|
|
926
1072
|
|
927
1073
|
desc 'Select a section to display from a menu'
|
928
1074
|
command :choose do |c|
|
929
|
-
c.action do |
|
1075
|
+
c.action do |_global_options, _options, _args|
|
930
1076
|
section = wwid.choose_section
|
931
|
-
puts wwid.list_section({:
|
1077
|
+
puts wwid.list_section({ section: section.cap_first, count: 0 })
|
932
1078
|
end
|
933
1079
|
end
|
934
1080
|
|
935
1081
|
desc 'Add a new section to the "doing" file'
|
936
|
-
arg_name '
|
1082
|
+
arg_name 'SECTION_NAME'
|
937
1083
|
command :add_section do |c|
|
938
|
-
c.action do |
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
raise "Section #{args[0]} already exists"
|
944
|
-
end
|
1084
|
+
c.action do |_global_options, _options, args|
|
1085
|
+
raise "Section #{args[0]} already exists" if wwid.sections.include?(args[0])
|
1086
|
+
|
1087
|
+
wwid.add_section(args[0].cap_first)
|
1088
|
+
wwid.write(wwid.doing_file)
|
945
1089
|
end
|
946
1090
|
end
|
947
1091
|
|
948
1092
|
desc 'List available color variables for configuration templates and views'
|
949
1093
|
command :colors do |c|
|
950
|
-
c.action do |
|
1094
|
+
c.action do |_global_options, _options, _args|
|
951
1095
|
clrs = wwid.colors
|
952
1096
|
bgs = []
|
953
1097
|
fgs = []
|
954
|
-
clrs.each
|
1098
|
+
clrs.each do |k, v|
|
955
1099
|
if k =~ /bg/
|
956
1100
|
bgs.push("#{v} #{clrs['default']} <-- #{k}")
|
957
1101
|
else
|
958
1102
|
fgs.push("#{v}XXXX#{clrs['default']} <-- #{k}")
|
959
1103
|
end
|
960
|
-
|
1104
|
+
end
|
961
1105
|
puts fgs.join("\n")
|
962
1106
|
puts bgs.join("\n")
|
963
1107
|
end
|
964
1108
|
end
|
965
1109
|
|
966
1110
|
desc 'Display a user-created view'
|
967
|
-
arg_name '
|
1111
|
+
arg_name 'VIEW_NAME'
|
968
1112
|
command :view do |c|
|
969
1113
|
c.desc 'Section (override view settings)'
|
970
|
-
c.
|
1114
|
+
c.arg_name 'NAME'
|
1115
|
+
c.flag %i[s section]
|
971
1116
|
|
972
1117
|
c.desc 'Count to display (override view settings)'
|
973
|
-
c.
|
1118
|
+
c.arg_name 'COUNT'
|
1119
|
+
c.flag %i[c count], must_match: /^\d+$/, type: Integer
|
974
1120
|
|
975
|
-
c.desc 'Output to export format (csv|html|json)'
|
976
|
-
c.
|
1121
|
+
c.desc 'Output to export format (csv|html|json|template|timeline)'
|
1122
|
+
c.arg_name 'FORMAT'
|
1123
|
+
c.flag %i[o output], must_match: /^(template|html|csv|json|timeline)$/i
|
977
1124
|
|
978
1125
|
c.desc 'Show time intervals on @done tasks'
|
979
|
-
c.switch [
|
1126
|
+
c.switch %i[t times], default_value: true
|
980
1127
|
|
981
1128
|
c.desc 'Show intervals with totals at the end of output'
|
982
|
-
c.switch [:totals], :
|
1129
|
+
c.switch [:totals], default_value: false, negatable: true
|
1130
|
+
|
1131
|
+
c.desc 'Include colors in output'
|
1132
|
+
c.switch [:color], default_value: true, negatable: true
|
983
1133
|
|
984
1134
|
c.desc 'Sort tags by (name|time)'
|
985
1135
|
default = 'time'
|
986
|
-
if wwid.config.
|
987
|
-
|
988
|
-
|
989
|
-
c.flag [:tag_sort], :default_value => default
|
1136
|
+
default = wwid.config['tag_sort'] if wwid.config.key?('tag_sort')
|
1137
|
+
c.arg_name 'KEY'
|
1138
|
+
c.flag [:tag_sort], must_match: /^(name|time)$/i, default_value: default
|
990
1139
|
|
991
1140
|
c.desc 'Only show items with recorded time intervals'
|
992
|
-
c.switch [:only_timed], :
|
1141
|
+
c.switch [:only_timed], default_value: false, negatable: true
|
993
1142
|
|
994
|
-
c.action do |
|
995
|
-
if args.empty?
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1143
|
+
c.action do |_global_options, options, args|
|
1144
|
+
title = if args.empty?
|
1145
|
+
wwid.choose_view
|
1146
|
+
else
|
1147
|
+
wwid.guess_view(args[0])
|
1148
|
+
end
|
1000
1149
|
|
1001
|
-
if options[:s]
|
1002
|
-
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
1003
|
-
end
|
1150
|
+
section = wwid.guess_section(options[:s]) || options[:s].cap_first if options[:s]
|
1004
1151
|
|
1005
1152
|
view = wwid.get_view(title)
|
1006
1153
|
if view
|
1007
|
-
if (view.
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
template = view.
|
1014
|
-
format = view.
|
1015
|
-
tags_color = view.
|
1154
|
+
only_timed = if (view.key?('only_timed') && view['only_timed']) || options[:only_timed]
|
1155
|
+
true
|
1156
|
+
else
|
1157
|
+
false
|
1158
|
+
end
|
1159
|
+
|
1160
|
+
template = view.key?('template') ? view['template'] : nil
|
1161
|
+
format = view.key?('date_format') ? view['date_format'] : nil
|
1162
|
+
tags_color = view.key?('tags_color') ? view['tags_color'] : nil
|
1016
1163
|
tag_filter = false
|
1017
|
-
if view.
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
tag_filter['bool'] = view.has_key?('tags_bool') && !view['tags_bool'].nil? ? view['tags_bool'].upcase : "OR"
|
1026
|
-
end
|
1164
|
+
if view.key?('tags') && !(view['tags'].nil? || view['tags'].empty?)
|
1165
|
+
tag_filter = { 'tags' => [], 'bool' => 'OR' }
|
1166
|
+
tag_filter['tags'] = if view['tags'].instance_of?(Array)
|
1167
|
+
view['tags'].map(&:strip)
|
1168
|
+
else
|
1169
|
+
view['tags'].gsub(/[, ]+/, ' ').split(' ').map(&:strip)
|
1170
|
+
end
|
1171
|
+
tag_filter['bool'] = view.key?('tags_bool') && !view['tags_bool'].nil? ? view['tags_bool'].upcase : 'OR'
|
1027
1172
|
end
|
1028
1173
|
|
1029
1174
|
# If the -o/--output flag was specified, override any default in the view template
|
1030
|
-
options[:o] ||= view.
|
1031
|
-
|
1032
|
-
count =
|
1033
|
-
|
1034
|
-
|
1175
|
+
options[:o] ||= view.key?('output_format') ? view['output_format'] : 'template'
|
1176
|
+
|
1177
|
+
count = if options[:c]
|
1178
|
+
options[:c]
|
1179
|
+
else
|
1180
|
+
view.key?('count') ? view['count'] : 10
|
1181
|
+
end
|
1182
|
+
section = if options[:s]
|
1183
|
+
section
|
1184
|
+
else
|
1185
|
+
view.key?('section') ? view['section'] : wwid.current_section
|
1186
|
+
end
|
1187
|
+
order = view.key?('order') ? view['order'] : 'asc'
|
1035
1188
|
|
1036
1189
|
options[:t] = true if options[:totals]
|
1037
|
-
options[:output]
|
1190
|
+
options[:output]&.downcase!
|
1038
1191
|
options[:sort_tags] = options[:tag_sort] =~ /^n/i
|
1039
1192
|
|
1040
|
-
|
1193
|
+
opts = {
|
1194
|
+
count: count,
|
1195
|
+
format: format,
|
1196
|
+
highlight: options[:color],
|
1197
|
+
only_timed: only_timed,
|
1198
|
+
order: order,
|
1199
|
+
output: options[:o],
|
1200
|
+
section: section,
|
1201
|
+
sort_tags: options[:sort_tags],
|
1202
|
+
tag_filter: tag_filter,
|
1203
|
+
tags_color: tags_color,
|
1204
|
+
template: template,
|
1205
|
+
times: options[:t],
|
1206
|
+
totals: options[:totals]
|
1207
|
+
}
|
1208
|
+
|
1209
|
+
puts wwid.list_section(opts)
|
1210
|
+
elsif title.instance_of?(FalseClass)
|
1211
|
+
exit_now! 'Cancelled'
|
1041
1212
|
else
|
1042
|
-
|
1043
|
-
exit_now! "Cancelled"
|
1044
|
-
else
|
1045
|
-
raise "View #{title} not found in config"
|
1046
|
-
end
|
1213
|
+
raise "View #{title} not found in config"
|
1047
1214
|
end
|
1048
1215
|
end
|
1049
1216
|
end
|
@@ -1051,124 +1218,135 @@ end
|
|
1051
1218
|
desc 'List available custom views'
|
1052
1219
|
command :views do |c|
|
1053
1220
|
c.desc 'List in single column'
|
1054
|
-
c.switch [
|
1221
|
+
c.switch %i[c column], default_value: false
|
1055
1222
|
|
1056
|
-
c.action do |
|
1223
|
+
c.action do |_global_options, options, _args|
|
1057
1224
|
joiner = options[:c] ? "\n" : "\t"
|
1058
1225
|
print wwid.views.join(joiner)
|
1059
1226
|
end
|
1060
1227
|
end
|
1061
1228
|
|
1062
|
-
desc 'Move entries
|
1063
|
-
arg_name '
|
1229
|
+
desc 'Move entries between sections'
|
1230
|
+
arg_name 'SECTION_NAME'
|
1064
1231
|
default_value wwid.current_section
|
1065
1232
|
command :archive do |c|
|
1066
1233
|
c.desc 'Count to keep (ignored if archiving by tag)'
|
1067
|
-
c.
|
1234
|
+
c.arg_name 'COUNT'
|
1235
|
+
c.flag %i[k keep], default_value: 5, must_match: /^\d+$/, type: Integer
|
1068
1236
|
|
1069
1237
|
c.desc 'Move entries to'
|
1070
|
-
c.
|
1238
|
+
c.arg_name 'SECTION_NAME'
|
1239
|
+
c.flag %i[t to], default_value: 'Archive'
|
1071
1240
|
|
1072
|
-
c.desc 'Tag
|
1073
|
-
c.
|
1241
|
+
c.desc 'Tag filter, combine multiple tags with a comma. Added for compatibility with other commands.'
|
1242
|
+
c.arg_name 'TAG'
|
1243
|
+
c.flag [:tag]
|
1074
1244
|
|
1075
|
-
c.
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
section = args[0].cap_first
|
1082
|
-
tags = args.length > 1 ? args[1..-1].map {|t| t.sub(/^@/,'').strip } : nil
|
1083
|
-
end
|
1084
|
-
else
|
1245
|
+
c.desc 'Tag boolean (AND|OR|NOT)'
|
1246
|
+
c.arg_name 'BOOLEAN'
|
1247
|
+
c.flag [:bool], must_match: /(and|or|not)/i, default_value: 'AND'
|
1248
|
+
|
1249
|
+
c.action do |_global_options, options, args|
|
1250
|
+
if args.empty?
|
1085
1251
|
section = wwid.current_section
|
1086
|
-
tags =
|
1252
|
+
tags = []
|
1253
|
+
elsif args[0] =~ /^@\S+/
|
1254
|
+
section = 'all'
|
1255
|
+
tags = args.map { |t| t.sub(/^@/, '').strip }
|
1256
|
+
else
|
1257
|
+
section = args[0].cap_first
|
1258
|
+
tags = args.length > 1 ? args[1..].map { |t| t.sub(/^@/, '').strip } : nil
|
1087
1259
|
end
|
1088
|
-
|
1260
|
+
|
1261
|
+
tags.concat(options[:tag].split(/ *, */).map { |t| t.sub(/^@/, '').strip }) if options[:tag]
|
1262
|
+
|
1263
|
+
wwid.archive(section, options[:keep], options[:to], tags, options[:bool])
|
1089
1264
|
end
|
1090
1265
|
end
|
1091
1266
|
|
1092
1267
|
desc 'Open the "doing" file in an editor'
|
1268
|
+
long_desc "`doing open` defaults to using the editor_app setting in #{wwid.config_file} (#{wwid.config.key?('editor_app') ? wwid.config['editor_app'] : 'not set'})"
|
1093
1269
|
command :open do |c|
|
1094
|
-
if `uname` =~ /Darwin/
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
end
|
1103
|
-
c.desc
|
1104
|
-
c.switch [
|
1270
|
+
if `uname` =~ /Darwin/
|
1271
|
+
c.desc 'Open with app name'
|
1272
|
+
c.arg_name 'APP_NAME'
|
1273
|
+
c.flag [:a]
|
1274
|
+
|
1275
|
+
c.desc 'Open with app bundle id'
|
1276
|
+
c.arg_name 'BUNDLE_ID'
|
1277
|
+
c.flag [:b]
|
1278
|
+
end
|
1279
|
+
c.desc "Open with $EDITOR (#{ENV['EDITOR']})"
|
1280
|
+
c.switch %i[e editor], negatable: false, default_value: false
|
1105
1281
|
|
1106
|
-
c.action do |
|
1282
|
+
c.action do |_global_options, options, _args|
|
1107
1283
|
params = options.dup
|
1108
|
-
params.delete_if
|
1109
|
-
k.
|
1110
|
-
|
1284
|
+
params.delete_if do |k, v|
|
1285
|
+
k.instance_of?(String) || v.nil? || v == false
|
1286
|
+
end
|
1111
1287
|
if `uname` =~ /Darwin/
|
1112
|
-
if params.length < 2
|
1113
1288
|
if options[:a]
|
1114
|
-
system %
|
1289
|
+
system %(open -a "#{options[:a]}" "#{File.expand_path(wwid.doing_file)}")
|
1115
1290
|
elsif options[:b]
|
1116
|
-
system %
|
1291
|
+
system %(open -b "#{options[:b]}" "#{File.expand_path(wwid.doing_file)}")
|
1117
1292
|
elsif options[:e]
|
1118
|
-
raise
|
1119
|
-
|
1293
|
+
raise 'No EDITOR variable defined in environment' if ENV['EDITOR'].nil?
|
1294
|
+
|
1295
|
+
system %($EDITOR "#{File.expand_path(wwid.doing_file)}")
|
1296
|
+
elsif wwid.config.key?('editor_app') && !wwid.config['editor_app'].nil?
|
1297
|
+
system %(open -a "#{wwid.config['editor_app']}" "#{File.expand_path(wwid.doing_file)}")
|
1120
1298
|
else
|
1121
|
-
|
1122
|
-
system %Q{open -a "#{wwid.config['editor_app']}" "#{File.expand_path(wwid.doing_file)}"}
|
1123
|
-
else
|
1124
|
-
system %Q{open "#{File.expand_path(wwid.doing_file)}"}
|
1125
|
-
end
|
1299
|
+
system %(open "#{File.expand_path(wwid.doing_file)}")
|
1126
1300
|
end
|
1301
|
+
|
1127
1302
|
else
|
1128
|
-
raise
|
1129
|
-
|
1130
|
-
|
1131
|
-
raise "No EDITOR variable defined in environment" if ENV['EDITOR'].nil?
|
1132
|
-
system %Q{$EDITOR "#{File.expand_path(wwid.doing_file)}"}
|
1303
|
+
raise 'No EDITOR variable defined in environment' if ENV['EDITOR'].nil?
|
1304
|
+
|
1305
|
+
system %($EDITOR "#{File.expand_path(wwid.doing_file)}")
|
1133
1306
|
end
|
1134
1307
|
end
|
1135
1308
|
end
|
1136
1309
|
|
1137
|
-
|
1138
1310
|
desc 'Edit the configuration file'
|
1139
1311
|
command :config do |c|
|
1140
1312
|
c.desc 'Editor to use'
|
1141
|
-
c.
|
1313
|
+
c.arg_name 'EDITOR'
|
1314
|
+
c.flag %i[e editor], default_value: nil
|
1142
1315
|
|
1143
|
-
if `uname` =~ /
|
1316
|
+
if `uname` =~ /Darwin/
|
1144
1317
|
c.desc 'Application to use'
|
1318
|
+
c.arg_name 'APP_NAME'
|
1145
1319
|
c.flag [:a]
|
1146
1320
|
|
1147
|
-
c.desc "Use the editor_app defined in ~/.doingrc (#{wwid.config['editor_app']})"
|
1148
|
-
c.switch [:x]
|
1149
|
-
|
1150
1321
|
c.desc 'Application bundle id to use'
|
1322
|
+
c.arg_name 'BUNDLE_ID'
|
1151
1323
|
c.flag [:b]
|
1324
|
+
|
1325
|
+
c.desc "Use the config_editor_app defined in ~/.doingrc (#{wwid.config.key?('config_editor_app') ? wwid.config['config_editor_app'] : 'config_editor_app not set'})"
|
1326
|
+
c.switch [:x]
|
1152
1327
|
end
|
1153
|
-
|
1154
|
-
|
1328
|
+
|
1329
|
+
c.action do |_global_options, options, _args|
|
1330
|
+
if `uname` =~ /Darwin/
|
1155
1331
|
if options[:x]
|
1156
|
-
|
1332
|
+
`open -a "#{wwid.config['config_editor_app']}" "#{wwid.config_file}"`
|
1157
1333
|
elsif options[:a] || options[:b]
|
1158
1334
|
if options[:a]
|
1159
|
-
|
1335
|
+
`open -a "#{options[:a]}" "#{wwid.config_file}"`
|
1160
1336
|
elsif options[:b]
|
1161
|
-
|
1337
|
+
`open -b #{options[:b]} "#{wwid.config_file}"`
|
1162
1338
|
end
|
1163
1339
|
else
|
1164
|
-
raise
|
1340
|
+
raise 'No EDITOR variable defined in environment' if options[:e].nil? && ENV['EDITOR'].nil?
|
1341
|
+
|
1165
1342
|
editor = options[:e].nil? ? ENV['EDITOR'] : options[:e]
|
1166
|
-
system %
|
1343
|
+
system %(#{editor} "#{wwid.config_file}")
|
1167
1344
|
end
|
1168
1345
|
else
|
1169
|
-
raise
|
1346
|
+
raise 'No EDITOR variable defined in environment' if options[:e].nil? && ENV['EDITOR'].nil?
|
1347
|
+
|
1170
1348
|
editor = options[:e].nil? ? ENV['EDITOR'] : options[:e]
|
1171
|
-
system %
|
1349
|
+
system %(#{editor} "#{wwid.config_file}")
|
1172
1350
|
end
|
1173
1351
|
end
|
1174
1352
|
end
|
@@ -1176,19 +1354,19 @@ end
|
|
1176
1354
|
desc 'Undo the last change to the doing_file'
|
1177
1355
|
command :undo do |c|
|
1178
1356
|
c.desc 'Specify alternate doing file'
|
1179
|
-
c.
|
1357
|
+
c.arg_name 'PATH'
|
1358
|
+
c.flag %i[f file], default_value: wwid.doing_file
|
1180
1359
|
|
1181
|
-
c.action do |
|
1360
|
+
c.action do |_global_options, options, _args|
|
1182
1361
|
file = options[:f] || wwid.doing_file
|
1183
1362
|
wwid.restore_backup(file)
|
1184
1363
|
end
|
1185
1364
|
end
|
1186
1365
|
|
1187
|
-
|
1188
|
-
|
1189
|
-
if global[:config_file]
|
1366
|
+
pre do |global, _command, _options, _args|
|
1367
|
+
if global[:config_file] && global[:config_file] != wwid.config_file
|
1190
1368
|
wwid.config_file = global[:config_file]
|
1191
|
-
wwid.configure({:
|
1369
|
+
wwid.configure({ ignore_local: true })
|
1192
1370
|
# wwid.results.push("Override config file #{wwid.config_file}")
|
1193
1371
|
end
|
1194
1372
|
|
@@ -1202,9 +1380,7 @@ pre do |global,command,options,args|
|
|
1202
1380
|
|
1203
1381
|
wwid.config[:include_notes] = false unless global[:notes]
|
1204
1382
|
|
1205
|
-
if global[:version]
|
1206
|
-
$stdout.puts "doing v" + Doing::VERSION
|
1207
|
-
end
|
1383
|
+
$stdout.puts "doing v#{Doing::VERSION}" if global[:version]
|
1208
1384
|
|
1209
1385
|
# Return true to proceed; false to abort and not call the
|
1210
1386
|
# chosen command
|
@@ -1213,7 +1389,7 @@ pre do |global,command,options,args|
|
|
1213
1389
|
true
|
1214
1390
|
end
|
1215
1391
|
|
1216
|
-
post do |global,
|
1392
|
+
post do |global, _command, _options, _args|
|
1217
1393
|
# Use skips_post before a command to skip this
|
1218
1394
|
# block on that command only
|
1219
1395
|
if global[:stdout]
|
@@ -1223,7 +1399,7 @@ post do |global,command,options,args|
|
|
1223
1399
|
end
|
1224
1400
|
end
|
1225
1401
|
|
1226
|
-
on_error do |
|
1402
|
+
on_error do |_exception|
|
1227
1403
|
# puts exception.message
|
1228
1404
|
true
|
1229
1405
|
end
|