doing 2.1.14 → 2.1.15

Sign up to get free protection for your applications and to get access to all the features.
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