doing 2.1.14 → 2.1.15

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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.irbrc +1 -0
  3. data/.yardoc/checksums +11 -9
  4. data/.yardoc/object_types +0 -0
  5. data/.yardoc/objects/root.dat +0 -0
  6. data/CHANGELOG.md +18 -0
  7. data/Gemfile.lock +3 -2
  8. data/README.md +56 -19
  9. data/bin/doing +4 -3
  10. data/docs/doc/Array.html +117 -3
  11. data/docs/doc/BooleanTermParser/Clause.html +1 -1
  12. data/docs/doc/BooleanTermParser/Operator.html +1 -1
  13. data/docs/doc/BooleanTermParser/Query.html +1 -1
  14. data/docs/doc/BooleanTermParser/QueryParser.html +1 -1
  15. data/docs/doc/BooleanTermParser/QueryTransformer.html +1 -1
  16. data/docs/doc/BooleanTermParser.html +1 -1
  17. data/docs/doc/Doing/Color.html +1 -1
  18. data/docs/doc/Doing/Completion.html +1 -1
  19. data/docs/doc/Doing/Configuration.html +5 -2
  20. data/docs/doc/Doing/Errors/DoingNoTraceError.html +1 -1
  21. data/docs/doc/Doing/Errors/DoingRuntimeError.html +1 -1
  22. data/docs/doc/Doing/Errors/DoingStandardError.html +1 -1
  23. data/docs/doc/Doing/Errors/EmptyInput.html +1 -1
  24. data/docs/doc/Doing/Errors/NoResults.html +1 -1
  25. data/docs/doc/Doing/Errors/PluginException.html +1 -1
  26. data/docs/doc/Doing/Errors/UserCancelled.html +1 -1
  27. data/docs/doc/Doing/Errors/WrongCommand.html +1 -1
  28. data/docs/doc/Doing/Errors.html +1 -1
  29. data/docs/doc/Doing/Hooks.html +1 -1
  30. data/docs/doc/Doing/Item.html +106 -2
  31. data/docs/doc/Doing/Items.html +2 -2
  32. data/docs/doc/Doing/LogAdapter.html +1 -1
  33. data/docs/doc/Doing/Note.html +2 -2
  34. data/docs/doc/Doing/Pager.html +1 -1
  35. data/docs/doc/Doing/Plugins.html +1 -1
  36. data/docs/doc/Doing/Prompt.html +1 -1
  37. data/docs/doc/Doing/Section.html +1 -1
  38. data/docs/doc/Doing/TemplateString.html +2 -2
  39. data/docs/doc/Doing/Util/Backup.html +1 -1
  40. data/docs/doc/Doing/Util.html +1 -1
  41. data/docs/doc/Doing/WWID.html +35 -65
  42. data/docs/doc/Doing.html +3 -3
  43. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
  44. data/docs/doc/GLI/Commands.html +1 -1
  45. data/docs/doc/GLI.html +1 -1
  46. data/docs/doc/Hash.html +1 -1
  47. data/docs/doc/Numeric.html +279 -0
  48. data/docs/doc/PhraseParser/Operator.html +1 -1
  49. data/docs/doc/PhraseParser/PhraseClause.html +1 -1
  50. data/docs/doc/PhraseParser/Query.html +1 -1
  51. data/docs/doc/PhraseParser/QueryParser.html +1 -1
  52. data/docs/doc/PhraseParser/QueryTransformer.html +1 -1
  53. data/docs/doc/PhraseParser/TermClause.html +1 -1
  54. data/docs/doc/PhraseParser.html +1 -1
  55. data/docs/doc/Status.html +1 -1
  56. data/docs/doc/String.html +767 -115
  57. data/docs/doc/Symbol.html +1 -1
  58. data/docs/doc/Time.html +1 -1
  59. data/docs/doc/_index.html +14 -9
  60. data/docs/doc/class_list.html +1 -1
  61. data/docs/doc/file.README.html +41 -15
  62. data/docs/doc/index.html +41 -15
  63. data/docs/doc/method_list.html +357 -293
  64. data/docs/doc/top-level-namespace.html +2 -2
  65. data/docs/index.md +56 -19
  66. data/doing.gemspec +1 -0
  67. data/doing.rdoc +3 -3
  68. data/example_plugin.rb +2 -4
  69. data/lib/completion/_doing.zsh +3 -3
  70. data/lib/completion/doing.bash +4 -4
  71. data/lib/completion/doing.fish +2 -2
  72. data/lib/doing/array_chronify.rb +57 -0
  73. data/lib/doing/configuration.rb +4 -1
  74. data/lib/doing/item.rb +32 -0
  75. data/lib/doing/log_adapter.rb +1 -1
  76. data/lib/doing/numeric_chronify.rb +40 -0
  77. data/lib/doing/plugins/export/dayone_export.rb +1 -1
  78. data/lib/doing/plugins/export/json_export.rb +2 -2
  79. data/lib/doing/plugins/export/template_export.rb +47 -90
  80. data/lib/doing/string.rb +97 -33
  81. data/lib/doing/string_chronify.rb +83 -13
  82. data/lib/doing/time.rb +4 -4
  83. data/lib/doing/util_backup.rb +1 -1
  84. data/lib/doing/version.rb +1 -1
  85. data/lib/doing/wwid.rb +58 -83
  86. data/lib/doing.rb +30 -27
  87. data/lib/examples/plugins/say_export.rb +1 -4
  88. metadata +26 -2
@@ -86,7 +86,7 @@
86
86
 
87
87
 
88
88
 
89
- <strong class="classes">Classes:</strong> <span class='object_link'><a href="Array.html" title="Array (class)">Array</a></span>, <span class='object_link'><a href="Hash.html" title="Hash (class)">Hash</a></span>, <span class='object_link'><a href="String.html" title="String (class)">String</a></span>, <span class='object_link'><a href="Symbol.html" title="Symbol (class)">Symbol</a></span>, <span class='object_link'><a href="Time.html" title="Time (class)">Time</a></span>
89
+ <strong class="classes">Classes:</strong> <span class='object_link'><a href="Array.html" title="Array (class)">Array</a></span>, <span class='object_link'><a href="Hash.html" title="Hash (class)">Hash</a></span>, <span class='object_link'><a href="Numeric.html" title="Numeric (class)">Numeric</a></span>, <span class='object_link'><a href="String.html" title="String (class)">String</a></span>, <span class='object_link'><a href="Symbol.html" title="Symbol (class)">Symbol</a></span>, <span class='object_link'><a href="Time.html" title="Time (class)">Time</a></span>
90
90
 
91
91
 
92
92
  </p>
@@ -102,7 +102,7 @@
102
102
  </div>
103
103
 
104
104
  <div id="footer">
105
- Generated on Sat Jan 15 17:27:48 2022 by
105
+ Generated on Mon Jan 17 08:01:48 2022 by
106
106
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
107
107
  0.9.26 (ruby-3.0.1).
108
108
  </div>
data/docs/index.md CHANGED
@@ -1,53 +1,90 @@
1
1
  # doing
2
2
 
3
- **A command line tool for remembering what you were doing and tracking what you've done.**
3
+ **A command line tool for remembering what you were doing and tracking what
4
+ you've done.**
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
+ _If you're one of the rare people like me who find this useful, feel free to
7
+ [buy me some coffee][donate]._
6
8
 
7
9
 
8
10
 
9
- The current version of `doing` is 2.1.12.
11
+ The current version of `doing` is 2.1.13.
10
12
 
11
- Find all of the documentation in the [doing wiki](https://github.com/ttscoff/doing/wiki).
13
+ Find all of the documentation in the [doing wiki][wiki].
12
14
 
13
- See [what's new in Doing 2.0](https://brettterpstra.com/2021/11/20/doing-2-dot-0/).
15
+ See [what's new in Doing 2.0][doing 2].
14
16
 
15
- Check out some craziness with Doing in the [iTerm status bar](https://brettterpstra.com/2021/10/15/see-what-youre-doing-in-the-iterm-status-bar/) and the [Mac Touch Bar/menu bar](https://brettterpstra.com/2021/07/21/crazy-bettertouchtool-touch-bar-simulator/).
17
+ Check out some craziness with Doing in the [iTerm status bar][status bar] and
18
+ the [Mac Touch Bar/menu bar][touch bar].
16
19
 
17
20
  ## What and why
18
21
 
19
- `doing` is a basic CLI for adding and listing "what was I doing" reminders in a [TaskPaper-formatted](https://www.taskpaper.com) text file. It allows for multiple sections/categories and flexible output formatting.
22
+ `doing` is a basic CLI for adding and listing "what was I doing" reminders in a
23
+ [TaskPaper-formatted](https://www.taskpaper.com) text file. It allows for
24
+ multiple sections/categories and flexible output formatting.
20
25
 
21
- While I'm working, I have hourly reminders to record what I'm working on, and I try to remember to punch in quick notes if I'm unexpectedly called away from a project. I can do this just by typing `doing now tracking down the CG bug`.
26
+ While I'm working, I have hourly reminders to record what I'm working on, and I
27
+ try to remember to punch in quick notes if I'm unexpectedly called away from a
28
+ project. I can do this just by typing `doing now tracking down the CG bug`.
22
29
 
23
- If there's something I want to look at later but doesn't need to be added to a task list or tracker, I can type `doing later check out the pinboard bookmarks from macdrifter`. When I get back to my computer --- or just need a refresher after a distraction --- I can type `doing last` to see what the last thing on my plate was. I can also type `doing recent` (or just `doing`) to get a list of the last few entries. `doing today` gives me everything since midnight for the current day, making it easy to see what I've accomplished over a sleepless night.
30
+ If there's something I want to look at later but doesn't need to be added to a
31
+ task list or tracker, I can type `doing later check out the pinboard bookmarks
32
+ from macdrifter`. When I get back to my computer --- or just need a refresher
33
+ after a distraction --- I can type `doing last` to see what the last thing on
34
+ my plate was. I can also type `doing recent` (or just `doing`) to get a list of
35
+ the last few entries. `doing today` gives me everything since midnight for the
36
+ current day, making it easy to see what I've accomplished over a sleepless
37
+ night.
24
38
 
25
- Doing has over 30 commands for tracking your status, recording your time, and analyzing the results.
39
+ Doing has over 30 commands for tracking your status, recording your time, and
40
+ analyzing the results.
26
41
 
27
- See [the wiki](https://github.com/ttscoff/doing/wiki) for installation and usage instructions.
42
+ See [the wiki][wiki] for installation and usage instructions.
28
43
 
29
44
  ## Launchbar/Alfred
30
45
 
31
- 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.
46
+ The LaunchBar action requires that `doing` be available in
47
+ `/usr/local/bin/doing`. If it's not (because you're using RVM or similar),
48
+ you'll need to symlink it there. Running the action with Return will show the
49
+ latest 9 items from Currently, along with any time intervals recorded, and
50
+ includes a submenu of Timers for each tag.
32
51
 
33
- 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.
52
+ Pressing Spacebar and typing allows you to add a new entry to currently. You an
53
+ also trigger a custom show command by typing "show [section/tag]" and hitting
54
+ return. Include any command line flags at the end of the string, and if you add
55
+ text in parenthesis, it will be processed as a note on the entry.
34
56
 
35
- Point of interest, the LaunchBar Action makes use of the `-o json` flag for outputting JSON to the action's script for parsing.
57
+ Point of interest, the LaunchBar Action makes use of the `-o json` flag for
58
+ outputting JSON to the action's script for parsing.
36
59
 
37
60
 
38
61
 
39
- See the [doing project on BrettTerpstra.com](https://brettterpstra.com/projects/doing/) for the download.
62
+ See the [doing project on BrettTerpstra.com][bt doing] for the download.
40
63
 
41
64
 
42
65
 
43
66
 
44
- Evan Lovely has [created an Alfred workflow as well](http://www.evanlovely.com/blog/technology/alfred-for-terpstras-doing/).
67
+ Evan Lovely has created an [Alfred workflow][] as well.
45
68
 
46
69
  ## Contributing
47
70
 
48
- If you [create a plugin](https://github.com/ttscoff/doing/wiki/Creating-Plugins), custom command, or hook you can share, please [let me know](https://brettterpstra.com/contact/). If I get a few plugin contributions, I'll set up a second repository for them.
49
-
50
- Feel free to fork [the repository](https://github.com/ttscoff/doing/) on GitHub and make pull requests with changes. Please target the `develop` branch with pull requests.
71
+ If you [create a plugin][], custom command, or hook you can share, please
72
+ [let me know][contact]. If I get a few plugin contributions, I'll set up a
73
+ second repository for them.
74
+
75
+ Feel free to fork [the repository][github] on GitHub and make pull requests
76
+ with changes. Please target the `develop` branch with pull requests.
77
+
78
+ [bt doing]: https://brettterpstra.com/projects/doing/
79
+ [donate]: http://brettterpstra.com/donate/
80
+ [github]: https://github.com/ttscoff/doing/
81
+ [wiki]: https://github.com/ttscoff/doing/wiki
82
+ [doing 2]: https://brettterpstra.com/2021/11/20/doing-2-dot-0/
83
+ [status bar]: https://brettterpstra.com/2021/10/15/see-what-youre-doing-in-the-iterm-status-bar/
84
+ [touch bar]: https://brettterpstra.com/2021/07/21/crazy-bettertouchtool-touch-bar-simulator/
85
+ [create a plugin]: https://github.com/ttscoff/doing/wiki/Creating-Plugins
86
+ [contact]: https://brettterpstra.com/contact/
87
+ [alfred workflow]: http://www.evanlovely.com/blog/technology/alfred-for-terpstras-doing/
51
88
 
52
89
 
53
90
 
data/doing.gemspec CHANGED
@@ -41,6 +41,7 @@ spec = Gem::Specification.new do |s|
41
41
  s.add_runtime_dependency('tty-which', '~> 0.5', '>= 0.5.0')
42
42
  s.add_runtime_dependency('tty-markdown', '~> 0.7', '>= 0.7.0')
43
43
  s.add_runtime_dependency('tty-reader', '~> 0.9', '>= 0.9.0')
44
+ s.add_runtime_dependency('tty-screen', '~> 0.8', '>= 0.8.1')
44
45
  s.add_runtime_dependency('parslet', '~> 2.0', '>= 2.0.0')
45
46
  s.add_runtime_dependency('plist', '~> 3.6', '>= 3.6.0')
46
47
  # s.add_runtime_dependency('amatch', '~> 0.4', '>= 0.4.0')
data/doing.rdoc CHANGED
@@ -5,7 +5,7 @@ record of what you've been doing, complete with tag-based time tracking. The
5
5
  command line tool allows you to add entries, annotate with tags and notes, and
6
6
  view your entries with myriad options, with a focus on a "natural" language syntax.
7
7
 
8
- v2.1.14
8
+ v2.1.15
9
9
 
10
10
  === Global Options
11
11
  === --config_file arg
@@ -557,7 +557,7 @@ Section
557
557
  [Default Value] None
558
558
 
559
559
 
560
- ===== -t|--took INTERVAL
560
+ ===== -t|--took|--for INTERVAL
561
561
 
562
562
  Set completion date to start date plus interval (XX[mhd] or HH:MM).
563
563
  If used without the --back option, the start date will be moved back to allow
@@ -645,7 +645,7 @@ Finish the last X entries matching search filter, surround with slashes for rege
645
645
  [Default Value] None
646
646
 
647
647
 
648
- ===== -t|--took INTERVAL
648
+ ===== -t|--took|--for INTERVAL
649
649
 
650
650
  Set the completed date to the start date plus XX[hmd]
651
651
 
data/example_plugin.rb CHANGED
@@ -152,11 +152,9 @@ module Doing
152
152
  finished_at = i.end_date
153
153
  took += finished_at.strftime('%A %B %e at %I:%M%p')
154
154
 
155
- d, h, m = wwid.format_time(interval)
155
+
156
156
  took += ' and it took'
157
- took += " #{d.to_i} days" if d.to_i.positive?
158
- took += " #{h.to_i} hours" if h.to_i.positive?
159
- took += " #{m.to_i} minutes" if m.to_i.positive?
157
+ took += interval.time_string(format: :natural)
160
158
  end
161
159
  end
162
160
 
@@ -106,13 +106,13 @@ function _doing() {
106
106
  args=( {-d,--dump}"[DEPRECATED]" {-u,--update}"[DEPRECATED]" )
107
107
  ;;
108
108
  done)
109
- args=( {-a,--archive}"[Immediately archive the entry]" "(--ask)--ask}[Prompt for note via multi-line input]" "(--at=)--at=}[Set finish date to specific date/time]" "(--started=)--started=}[Backdate start date by interval or set to time [4pm|20m|2h|"yesterday noon"]]" "(--date)--date}[Include date]" {-e,--editor}"[Edit entry with vim]" {-n,--note=}"[Include a note]" {-r,--remove}"[Remove @done tag]" {-s,--section=}"[Section]" {-t,--took=}"[Set completion date to start date plus interval]" {-u,--unfinished}"[Finish last entry not already marked @done]" )
109
+ args=( {-a,--archive}"[Immediately archive the entry]" "(--ask)--ask}[Prompt for note via multi-line input]" "(--at=)--at=}[Set finish date to specific date/time]" "(--started=)--started=}[Backdate start date by interval or set to time [4pm|20m|2h|"yesterday noon"]]" "(--date)--date}[Include date]" {-e,--editor}"[Edit entry with vim]" {-n,--note=}"[Include a note]" {-r,--remove}"[Remove @done tag]" {-s,--section=}"[Section]" "(--for=)--for=}[Set completion date to start date plus interval]" {-u,--unfinished}"[Finish last entry not already marked @done]" )
110
110
  ;;
111
111
  did)
112
- args=( {-a,--archive}"[Immediately archive the entry]" "(--ask)--ask}[Prompt for note via multi-line input]" "(--at=)--at=}[Set finish date to specific date/time]" "(--started=)--started=}[Backdate start date by interval or set to time [4pm|20m|2h|"yesterday noon"]]" "(--date)--date}[Include date]" {-e,--editor}"[Edit entry with vim]" {-n,--note=}"[Include a note]" {-r,--remove}"[Remove @done tag]" {-s,--section=}"[Section]" {-t,--took=}"[Set completion date to start date plus interval]" {-u,--unfinished}"[Finish last entry not already marked @done]" )
112
+ args=( {-a,--archive}"[Immediately archive the entry]" "(--ask)--ask}[Prompt for note via multi-line input]" "(--at=)--at=}[Set finish date to specific date/time]" "(--started=)--started=}[Backdate start date by interval or set to time [4pm|20m|2h|"yesterday noon"]]" "(--date)--date}[Include date]" {-e,--editor}"[Edit entry with vim]" {-n,--note=}"[Include a note]" {-r,--remove}"[Remove @done tag]" {-s,--section=}"[Section]" "(--for=)--for=}[Set completion date to start date plus interval]" {-u,--unfinished}"[Finish last entry not already marked @done]" )
113
113
  ;;
114
114
  finish)
115
- args=( {-a,--archive}"[Archive entries]" "(--at=)--at=}[Set finish date to specific date/time]" "(--auto)--auto}[Auto-generate finish dates from next entrys start times start time]" {-b,--back=}"[Backdate completed date to date string [4pm|20m|2h|yesterday noon]]" "(--bool=)--bool=}[Boolean]" "(--case=)--case=}[Case sensitivity for search string matching [(c)ase-sensitive]" "(--date)--date}[Include date]" {-i,--interactive}"[Select item(s) to finish from a menu of matching entries]" "(--not)--not}[Finish items that *dont* match search/tag filterst* match search/tag filters]" {-r,--remove}"[Remove done tag]" {-s,--section=}"[Section]" "(--search=)--search=}[Finish the last X entries matching search filter]" {-t,--took=}"[Set the completed date to the start date plus XX[hmd]]" "(--tag=)--tag=}[Finish the last X entries containing TAG]" {-u,--unfinished}"[Finish last entry]" "(--val=)--val=}[Perform a tag value query]" {-x,--exact}"[Force exact search string matching]" )
115
+ args=( {-a,--archive}"[Archive entries]" "(--at=)--at=}[Set finish date to specific date/time]" "(--auto)--auto}[Auto-generate finish dates from next entrys start times start time]" {-b,--back=}"[Backdate completed date to date string [4pm|20m|2h|yesterday noon]]" "(--bool=)--bool=}[Boolean]" "(--case=)--case=}[Case sensitivity for search string matching [(c)ase-sensitive]" "(--date)--date}[Include date]" {-i,--interactive}"[Select item(s) to finish from a menu of matching entries]" "(--not)--not}[Finish items that *dont* match search/tag filterst* match search/tag filters]" {-r,--remove}"[Remove done tag]" {-s,--section=}"[Section]" "(--search=)--search=}[Finish the last X entries matching search filter]" "(--for=)--for=}[Set the completed date to the start date plus XX[hmd]]" "(--tag=)--tag=}[Finish the last X entries containing TAG]" {-u,--unfinished}"[Finish last entry]" "(--val=)--val=}[Perform a tag value query]" {-x,--exact}"[Force exact search string matching]" )
116
116
  ;;
117
117
  grep)
118
118
  args=( "(--after=)--after=}[Search entries newer than date]" "(--before=)--before=}[Search entries older than date]" "(--bool=)--bool=}[Combine multiple tags or value queries using AND]" "(--case=)--case=}[Case sensitivity for search string matching [(c)ase-sensitive]" {-d,--delete}"[Delete matching entries]" "(--duration)--duration}[Show elapsed time on entries without @done tag]" {-e,--editor}"[Edit matching entries with vim]" "(--from=)--from=}[Date range to show]" {-i,--interactive}"[Display an interactive menu of results to perform further operations]" "(--not)--not}[Show items that *dont* match search stringt* match search string]" {-o,--output=}"[Output to export format]" "(--only_timed)--only_timed}[Only show items with recorded time intervals]" {-s,--section=}"[Section]" {-t,--times}"[Show time intervals on @done tasks]" "(--tag_sort=)--tag_sort=}[Sort tags by]" "(--totals)--totals}[Show intervals with totals at the end of output]" "(--val=)--val=}[Perform a tag value query]" {-x,--exact}"[Force exact string matching]" )
@@ -81,9 +81,9 @@ _doing_config() {
81
81
  _doing_done() {
82
82
 
83
83
  if [[ "$token" == --* ]]; then
84
- COMPREPLY=( $( compgen -W '--archive --ask --at --started --date --editor --note --remove --section --took --unfinished' -- $token ) )
84
+ COMPREPLY=( $( compgen -W '--archive --ask --at --started --date --editor --note --remove --section --for --unfinished' -- $token ) )
85
85
  elif [[ "$token" == -* ]]; then
86
- COMPREPLY=( $( compgen -W '-a -e -n -r -s -t -u --archive --ask --at --started --date --editor --note --remove --section --took --unfinished' -- $token ) )
86
+ COMPREPLY=( $( compgen -W '-a -e -n -r -s -u --archive --ask --at --started --date --editor --note --remove --section --for --unfinished' -- $token ) )
87
87
 
88
88
  fi
89
89
  }
@@ -91,9 +91,9 @@ _doing_done() {
91
91
  _doing_finish() {
92
92
 
93
93
  if [[ "$token" == --* ]]; then
94
- COMPREPLY=( $( compgen -W '--archive --at --auto --back --bool --case --date --interactive --not --remove --section --search --took --tag --unfinished --val --exact' -- $token ) )
94
+ COMPREPLY=( $( compgen -W '--archive --at --auto --back --bool --case --date --interactive --not --remove --section --search --for --tag --unfinished --val --exact' -- $token ) )
95
95
  elif [[ "$token" == -* ]]; then
96
- COMPREPLY=( $( compgen -W '-a -b -i -r -s -t -u -x --archive --at --auto --back --bool --case --date --interactive --not --remove --section --search --took --tag --unfinished --val --exact' -- $token ) )
96
+ COMPREPLY=( $( compgen -W '-a -b -i -r -s -u -x --archive --at --auto --back --bool --case --date --interactive --not --remove --section --search --for --tag --unfinished --val --exact' -- $token ) )
97
97
 
98
98
  fi
99
99
  }
@@ -155,7 +155,7 @@ complete -c doing -l editor -s e -f -n '__fish_doing_using_command done did' -d
155
155
  complete -c doing -l note -s n -f -r -n '__fish_doing_using_command done did' -d Include\ a\ note
156
156
  complete -c doing -l remove -s r -f -n '__fish_doing_using_command done did' -d Remove\ @done\ tag
157
157
  complete -c doing -l section -s s -f -r -n '__fish_doing_using_command done did' -d Section
158
- complete -c doing -l took -s t -f -r -n '__fish_doing_using_command done did' -d Set\ completion\ date\ to\ start\ date\ plus\ interval
158
+ complete -c doing -l for -f -r -n '__fish_doing_using_command done did' -d Set\ completion\ date\ to\ start\ date\ plus\ interval
159
159
  complete -c doing -l unfinished -s u -f -n '__fish_doing_using_command done did' -d Finish\ last\ entry\ not\ already\ marked\ @done
160
160
  complete -c doing -l archive -s a -f -n '__fish_doing_using_command finish' -d Archive\ entries
161
161
  complete -c doing -l at -f -r -n '__fish_doing_using_command finish' -d Set\ finish\ date\ to\ specific\ date/time
@@ -169,7 +169,7 @@ complete -c doing -l not -f -n '__fish_doing_using_command finish' -d Finish\
169
169
  complete -c doing -l remove -s r -f -n '__fish_doing_using_command finish' -d Remove\ done\ tag
170
170
  complete -c doing -l section -s s -f -r -n '__fish_doing_using_command finish' -d Section
171
171
  complete -c doing -l search -f -r -n '__fish_doing_using_command finish' -d Finish\ the\ last\ X\ entries\ matching\ search\ filter
172
- complete -c doing -l took -s t -f -r -n '__fish_doing_using_command finish' -d Set\ the\ completed\ date\ to\ the\ start\ date\ plus\ XX\[hmd\]
172
+ complete -c doing -l for -f -r -n '__fish_doing_using_command finish' -d Set\ the\ completed\ date\ to\ the\ start\ date\ plus\ XX\[hmd\]
173
173
  complete -c doing -l tag -f -r -n '__fish_doing_using_command finish' -d Finish\ the\ last\ X\ entries\ containing\ TAG
174
174
  complete -c doing -l unfinished -s u -f -n '__fish_doing_using_command finish' -d Finish\ last\ entry
175
175
  complete -c doing -l val -f -r -n '__fish_doing_using_command finish' -d Perform\ a\ tag\ value\ query
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doing
4
+ # Chronify array helpers
5
+ class ::Array
6
+ ##
7
+ ## Format [d, h, m] as string
8
+ ##
9
+ ## @param time [Array] Array of [days, hours,
10
+ ## minutes]
11
+ ## @param format [Symbol] The format, :dhm, :hm, :m, :clock, :natural
12
+ ## @return [String] formatted string
13
+ ##
14
+ def time_string(format: :dhm)
15
+ raise InvalidArgument, 'Invalid array, must be [d,h,m]' unless count == 3
16
+
17
+ d, h, m = self
18
+ case format
19
+ when :clock
20
+ format('%<d>02d:%<h>02d:%<m>02d', d: d, h: h, m: m)
21
+ when :dhm
22
+ output = []
23
+ output.push(format('%<d>dd', d: d)) if d.positive?
24
+ output.push(format('%<h>dh', h: h)) if h.positive?
25
+ output.push(format('%<m>dm', m: m)) if m.positive?
26
+ output.join(' ')
27
+ when :hm
28
+ h += d * 24 if d.positive?
29
+ format('%<h> 4dh %<m>02dm', h: h, m: m)
30
+ when :m
31
+ h += d * 24 if d.positive?
32
+ m += h * 60 if h.positive?
33
+ format('%<m> 4dm', m: m)
34
+ when :natural
35
+ human = []
36
+ human.push(format('%<d>d %<s>s', d: d, s: 'day'.to_p(d))) if d.positive?
37
+ human.push(format('%<h>d %<s>s', h: h, s: 'hour'.to_p(h))) if h.positive?
38
+ human.push(format('%<m>d %<s>s', m: m, s: 'minute'.to_p(m))) if m.positive?
39
+ human.join(', ')
40
+ when :speech
41
+ human = []
42
+ human.push(format('%<d>d %<s>s', d: d, s: 'day'.to_p(d))) if d.positive?
43
+ human.push(format('%<h>d %<s>s', h: h, s: 'hour'.to_p(h))) if h.positive?
44
+ human.push(format('%<m>d %<s>s', m: m, s: 'minute'.to_p(m))) if m.positive?
45
+ last = human.pop
46
+ case human.count
47
+ when 2
48
+ human.join(', ') + ", and #{last}"
49
+ when 1
50
+ "#{human[0]} and #{last}"
51
+ when 0
52
+ last
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -101,7 +101,10 @@ module Doing
101
101
  'distance' => 3,
102
102
  'case' => 'smart' # sensitive, ignore, smart
103
103
  },
104
- 'include_notes' => true
104
+ 'include_notes' => true,
105
+ 'interaction' => {
106
+ 'confirm_longer_than' => '5h'
107
+ }
105
108
  }
106
109
 
107
110
  def initialize(file = nil, options: {})
data/lib/doing/item.rb CHANGED
@@ -57,6 +57,25 @@ module Doing
57
57
  @end_date ||= Time.parse(Regexp.last_match(1)) if @title =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/
58
58
  end
59
59
 
60
+ def calculate_end_date(opt)
61
+ if opt[:took]
62
+ if @date + opt[:took] > Time.now
63
+ @date = Time.now - opt[:took]
64
+ Time.now
65
+ else
66
+ @date + opt[:took]
67
+ end
68
+ elsif opt[:back]
69
+ if opt[:back].is_a? Integer
70
+ @date + opt[:back]
71
+ else
72
+ @date + (opt[:back] - @date)
73
+ end
74
+ else
75
+ Time.now
76
+ end
77
+ end
78
+
60
79
  # Generate a hash that represents the entry
61
80
  #
62
81
  # @return [String] entry hash
@@ -112,6 +131,19 @@ module Doing
112
131
  (start_a >= start_b && start_a <= end_b) || (end_a >= start_b && end_a <= end_b) || (start_a < start_b && end_a > end_b)
113
132
  end
114
133
 
134
+ ##
135
+ ## Updates the title of the Item by expanding natural
136
+ ## language dates within configured date tags (tags
137
+ ## whose value is expected to be a date)
138
+ ##
139
+ ## @param additional_tags An array of additional
140
+ ## tag names to consider
141
+ ## dates
142
+ ##
143
+ def expand_date_tags(additional_tags = nil)
144
+ @title.expand_date_tags(additional_tags)
145
+ end
146
+
115
147
  ##
116
148
  ## Add (or remove) tags from the title of the item
117
149
  ##
@@ -52,7 +52,7 @@ module Doing
52
52
  COUNT_KEYS.each { |key| @counters[key] = { tag: [], count: 0 } }
53
53
  @results = []
54
54
  @logdev = $stderr
55
- @max_length = `tput cols`.strip.to_i - 5 || 85
55
+ @max_length = TTY::Screen.columns - 5 || 85
56
56
  self.log_level = level
57
57
  @prev_level = level
58
58
  end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doing
4
+ ##
5
+ ## Number helpers
6
+ ##
7
+ class ::Numeric
8
+ ##
9
+ ## Format human readable time from seconds
10
+ ##
11
+ ## @param seconds [Integer] Seconds
12
+ ##
13
+ def format_time(human: false)
14
+ return [0, 0, 0] if nil?
15
+
16
+ seconds = dup.to_i
17
+ minutes = (seconds / 60).to_i
18
+ hours = (minutes / 60).to_i
19
+ if human
20
+ minutes = (minutes % 60).to_i
21
+ [0, hours, minutes]
22
+ else
23
+ days = (hours / 24).to_i
24
+ hours = (hours % 24).to_i
25
+ minutes = (minutes % 60).to_i
26
+ [days, hours, minutes]
27
+ end
28
+ end
29
+
30
+ ##
31
+ ## Format seconds as natural language time string
32
+ ##
33
+ ## @param format [Symbol] The format to output
34
+ ## (:dhm, :hm, :m, :clock, :natural)
35
+ ##
36
+ def time_string(format: :dhm)
37
+ format_time(human: true).time_string(format: format)
38
+ end
39
+ end
40
+ end
@@ -84,7 +84,7 @@ module Doing
84
84
  interval ||= false
85
85
  human_time = false
86
86
  if interval
87
- d, h, m = wwid.format_time(wwid.get_interval(i, formatted: false))
87
+ d, h, m = wwid.get_interval(i, formatted: false).format_time
88
88
  human_times = []
89
89
  human_times << format('%<d>d day%<p>s', d: d, p: d == 1 ? '' : 's') if d > 0
90
90
  human_times << format('%<h>d hour%<p>s', h: h, p: h == 1 ? '' : 's') if h > 0
@@ -56,7 +56,7 @@ module Doing
56
56
  end_date: end_date,
57
57
  title: title.strip, #+ " #{note}"
58
58
  note: note.instance_of?(Array) ? note.to_s : note,
59
- time: '%02d:%02d:%02d' % wwid.format_time(interval),
59
+ time: interval.time_string(format: :clock),
60
60
  tags: tags
61
61
  }
62
62
 
@@ -68,7 +68,7 @@ module Doing
68
68
  new_item = {
69
69
  'id' => index + 1,
70
70
  'content' => title.strip, #+ " #{note}"
71
- 'title' => title.strip + " (#{'%02d:%02d:%02d' % wwid.format_time(interval)})",
71
+ 'title' => title.strip + " (#{interval.time_string(format: :clock)})",
72
72
  'start' => i.date.strftime('%F %T'),
73
73
  'type' => 'box',
74
74
  'style' => 'color:#4c566b;background-color:#d8dee9;'
@@ -5,6 +5,7 @@
5
5
  # author: Brett Terpstra
6
6
  # url: https://brettterpstra.com
7
7
  module Doing
8
+ # Template Export
8
9
  class TemplateExport
9
10
  include Doing::Color
10
11
  include Doing::Util
@@ -32,7 +33,7 @@ module Doing
32
33
 
33
34
  placeholders = {}
34
35
 
35
- if (!item.note.empty?) && wwid.config['include_notes']
36
+ if !item.note.empty? && wwid.config['include_notes']
36
37
  note = item.note.map(&:strip).delete_if(&:empty?)
37
38
  note.map! { |line| "#{line.sub(/^\t*/, '')} " }
38
39
 
@@ -42,122 +43,74 @@ module Doing
42
43
  line.simple_wrap(width)
43
44
  # line.chomp.gsub(/(.{1,#{width}})(\s+|\Z)/, "\\1\n")
44
45
  end
45
- note = note.delete_if(&:empty?)
46
+ note.delete_if(&:empty?)
46
47
  end
47
48
  else
48
49
  note = []
49
50
  end
50
51
 
51
- # output.sub!(/%(\d+)?date/) do
52
- # pad = Regexp.last_match(1).to_i
53
- # format("%#{pad}s", item.date.strftime(opt[:format]))
54
- # end
55
52
  placeholders['date'] = item.date.strftime(opt[:format])
56
53
 
57
54
  interval = wwid.get_interval(item, record: true, formatted: false) if opt[:times]
58
55
  if interval
59
- case opt[:interval_format].to_sym
60
- when :human
61
- _d, h, m = wwid.format_time(interval, human: true)
62
- interval = format('%<h> 4dh %<m>02dm', h: h, m: m)
63
- else
64
- d, h, m = wwid.format_time(interval)
65
- interval = format('%<d>02d:%<h>02d:%<m>02d', d: d, h: h, m: m)
66
- end
56
+ interval = case opt[:interval_format].to_sym
57
+ when :human
58
+ interval.time_string(format: :hm)
59
+ else
60
+ interval.time_string(format: :clock)
61
+ end
67
62
  end
68
63
 
69
64
  interval ||= ''
70
- # output.sub!(/%interval/, interval)
71
65
  placeholders['interval'] = interval
72
66
 
73
67
  duration = item.duration if opt[:duration]
74
68
  if duration
75
- case opt[:interval_format].to_sym
76
- when :human
77
- _d, h, m = wwid.format_time(duration, human: true)
78
- duration = format('%<h> 4dh %<m>02dm', h: h, m: m)
79
- else
80
- d, h, m = wwid.format_time(duration)
81
- duration = format('%<d>02d:%<h>02d:%<m>02d', d: d, h: h, m: m)
82
- end
69
+ duration = case opt[:interval_format].to_sym
70
+ when :human
71
+ duration.time_string(format: :hm)
72
+ else
73
+ duration.time_string(format: :clock)
74
+ end
83
75
  end
84
76
  duration ||= ''
85
- # output.sub!(/%duration/, duration)
86
77
  placeholders['duration'] = duration
87
78
 
88
- # output.sub!(/%(\d+)?shortdate/) do
89
- # pad = Regexp.last_match(1) || 13
90
- # format("%#{pad}s", item.date.relative_date)
91
- # end
92
- placeholders['shortdate'] = format("%13s", item.date.relative_date)
93
- # output.sub!(/%section/, item.section) if item.section
79
+ placeholders['shortdate'] = format('%13s', item.date.relative_date)
94
80
  placeholders['section'] = item.section || ''
95
81
  placeholders['title'] = item.title
96
-
97
- # title_rx = /(?mi)%(?<width>-?\d+)?(?:(?<ichar>[ _t])(?<icount>\d+))?(?<prefix>.[ _t]?)?title(?<after>.*?)$/
98
- # title_color = Doing::Color.reset + output.match(/(?mi)^(.*?)(%.*?title)/)[1].last_color
99
-
100
- # title_offset = Doing::Color.uncolor(output).match(title_rx).begin(0)
101
-
102
- # output.sub!(title_rx) do
103
- # m = Regexp.last_match
104
-
105
- # after = m['after']
106
- # pad = m['width'].to_i
107
- # indent = ''
108
- # if m['ichar']
109
- # char = m['ichar'] =~ /t/ ? "\t" : ' '
110
- # indent = char * m['icount'].to_i
111
- # end
112
- # prefix = m['prefix']
113
- # if opt[:wrap_width]&.positive? || pad.positive?
114
- # width = pad.positive? ? pad : opt[:wrap_width]
115
- # item.title.wrap(width, pad: pad, indent: indent, offset: title_offset, prefix: prefix, color: title_color, after: after, reset: reset)
116
- # # flag + item.title.gsub(/(.{#{opt[:wrap_width]}})(?=\s+|\Z)/, "\\1\n ").sub(/\s*$/, '') + reset
117
- # else
118
- # format("%s%#{pad}s%s", prefix, item.title.sub(/\s*$/, ''), after)
119
- # end
120
- # end
121
-
122
-
123
-
124
82
  placeholders['note'] = note
125
83
  placeholders['idnote'] = note.empty? ? '' : "\n#{note.map { |l| "\t\t#{l.strip} " }.join("\n")}"
126
84
  placeholders['odnote'] = note.empty? ? '' : "\n#{note.map { |l| "#{l.strip} " }.join("\n")}"
127
- placeholders['chompnote'] = note.empty? ? '' : note.map { |l| l.gsub(/\n+/, ' ').gsub(/(^\s*|\s*$)/, '').gsub(/\s+/, ' ') }.join(' ')
128
-
129
- # if note.empty?
130
- # output.gsub!(/%(chomp|[io]d|(\^.)?(([ _t]|[^a-z0-9])?\d+)?(.[ _t]?)?)?note/, '')
131
- # else
132
- # output.sub!(/%note/, "\n#{note.map { |l| "\t#{l.strip} " }.join("\n")}")
133
- # output.sub!(/%idnote/, "\n#{note.map { |l| "\t\t#{l.strip} " }.join("\n")}")
134
- # output.sub!(/%odnote/, "\n#{note.map { |l| "#{l.strip} " }.join("\n")}")
135
- # output.sub!(/(?mi)%(?:\^(?<mchar>.))?(?:(?<ichar>[ _t]|[^a-z0-9])?(?<icount>\d+))?(?<prefix>.[ _t]?)?note/) do
136
- # m = Regexp.last_match
137
- # mark = m['mchar'] || ''
138
- # indent = if m['ichar']
139
- # char = m['ichar'] =~ /t/ ? "\t" : ' '
140
- # char * m['icount'].to_i
141
- # else
142
- # ''
143
- # end
144
- # prefix = m['prefix'] || ''
145
- # "\n#{note.map { |l| "#{mark}#{indent}#{prefix}#{l.strip} " }.join("\n")}"
146
- # end
147
-
148
- # output.sub!(/%chompnote/) do
149
- # note.map { |l| l.gsub(/\n+/, ' ').gsub(/(^\s*|\s*$)/, '').gsub(/\s+/, ' ') }.join(' ')
150
- # end
151
- # end
152
85
 
153
- template = opt[:template].dup
154
- template.sub!(/(?i-m)^([\s\S]*?)(%(?:[io]d|(?:\^[\s\S])?(?:(?:[ _t]|[^a-z0-9])?\d+)?(?:[\s\S][ _t]?)?)?note)([\s\S]*?)$/, '\1\3\2')
155
- output = Doing::TemplateString.new(template, placeholders: placeholders, wrap_width: opt[:wrap_width], color: flag, tags_color: opt[:tags_color], reset: reset).colored
86
+ chompnote = []
87
+ unless note.empty?
88
+ chompnote = note.map do |l|
89
+ l.gsub(/\n+/, ' ').gsub(/(^\s*|\s*$)/, '').gsub(/\s+/, ' ')
90
+ end
91
+ end
92
+ placeholders['chompnote'] = chompnote.join(' ')
156
93
 
157
- output.gsub!(/(?<!\\)%hr(_under)?/) do
94
+ template = opt[:template].dup
95
+ note_rx = /(?i-m)(?x:^([\s\S]*?)
96
+ (%(?:[io]d|(?:\^[\s\S])?
97
+ (?:(?:[ _t]|[^a-z0-9])?\d+)?
98
+ (?:[\s\S][ _t]?)?)?note)
99
+ ([\s\S]*?)$)/
100
+ template.sub!(note_rx, '\1\3\2')
101
+ output = Doing::TemplateString.new(template,
102
+ color: flag,
103
+ placeholders: placeholders,
104
+ reset: reset,
105
+ tags_color: opt[:tags_color],
106
+ wrap_width: opt[:wrap_width]).colored
107
+
108
+ output.gsub!(/(?<!\\)%(\S)?hr(_under)?/) do
158
109
  o = ''
159
- `tput cols`.to_i.times do
160
- o += Regexp.last_match(1).nil? ? '-' : '_'
110
+ TTY::Screen.columns.to_i.times do
111
+ char = Regexp.last_match(2).nil? ? '-' : '_'
112
+ char = Regexp.last_match(1).nil? ? char : Regexp.last_match(1)
113
+ o += char
161
114
  end
162
115
  o
163
116
  end
@@ -170,7 +123,11 @@ module Doing
170
123
  end
171
124
 
172
125
  # Doing.logger.debug('Template Export:', "#{items.count} items output to template #{opt[:template]}")
173
- out += wwid.tag_times(format: wwid.config['timer_format'].to_sym, sort_by_name: opt[:sort_tags], sort_order: opt[:tag_order]) if opt[:totals]
126
+ if opt[:totals]
127
+ out += wwid.tag_times(format: wwid.config['timer_format'].to_sym,
128
+ sort_by_name: opt[:sort_tags],
129
+ sort_order: opt[:tag_order])
130
+ end
174
131
  out
175
132
  end
176
133