doing 2.1.0pre → 2.1.1pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardoc/checksums +3 -2
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/CHANGELOG.md +14 -11
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/bin/doing +112 -87
- data/doc/Array.html +1 -1
- data/doc/Doing/Color.html +1 -1
- data/doc/Doing/Completion.html +1 -1
- data/doc/Doing/Configuration.html +1 -1
- data/doc/Doing/Errors/DoingNoTraceError.html +1 -1
- data/doc/Doing/Errors/DoingRuntimeError.html +1 -1
- data/doc/Doing/Errors/DoingStandardError.html +1 -1
- data/doc/Doing/Errors/EmptyInput.html +1 -1
- data/doc/Doing/Errors/NoResults.html +1 -1
- data/doc/Doing/Errors/PluginException.html +1 -1
- data/doc/Doing/Errors/UserCancelled.html +1 -1
- data/doc/Doing/Errors/WrongCommand.html +1 -1
- data/doc/Doing/Errors.html +1 -1
- data/doc/Doing/Hooks.html +1 -1
- data/doc/Doing/Item.html +1 -1
- data/doc/Doing/Items.html +1 -1
- data/doc/Doing/LogAdapter.html +1 -1
- data/doc/Doing/Note.html +1 -1
- data/doc/Doing/Pager.html +1 -1
- data/doc/Doing/Plugins.html +1 -1
- data/doc/Doing/Prompt.html +1 -1
- data/doc/Doing/Section.html +1 -1
- data/doc/Doing/Util.html +1 -1
- data/doc/Doing/WWID.html +1 -181
- data/doc/Doing.html +3 -3
- data/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
- data/doc/GLI/Commands.html +1 -1
- data/doc/GLI.html +1 -1
- data/doc/Hash.html +1 -1
- data/doc/Status.html +1 -1
- data/doc/String.html +207 -3
- data/doc/Symbol.html +1 -1
- data/doc/Time.html +1 -1
- data/doc/_index.html +1 -1
- data/doc/file.README.html +2 -2
- data/doc/index.html +2 -2
- data/doc/method_list.html +84 -84
- data/doc/top-level-namespace.html +1 -1
- data/doing.rdoc +85 -18
- data/lib/completion/doing.bash +11 -11
- data/lib/doing/string_chronify.rb +81 -0
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +87 -75
- data/lib/doing.rb +1 -0
- metadata +2 -1
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.
|
|
8
|
+
v2.1.1pre
|
|
9
9
|
|
|
10
10
|
=== Global Options
|
|
11
11
|
=== --config_file arg
|
|
@@ -145,7 +145,7 @@ Repeat last entry matching tags. Combine multiple tags with a comma.
|
|
|
145
145
|
|
|
146
146
|
|
|
147
147
|
===== -e|--editor
|
|
148
|
-
Edit duplicated entry with
|
|
148
|
+
Edit duplicated entry with emacs -nw before adding
|
|
149
149
|
|
|
150
150
|
|
|
151
151
|
|
|
@@ -541,7 +541,7 @@ Include date
|
|
|
541
541
|
|
|
542
542
|
|
|
543
543
|
===== -e|--editor
|
|
544
|
-
Edit entry with
|
|
544
|
+
Edit entry with emacs -nw (with no arguments, edits the last entry)
|
|
545
545
|
|
|
546
546
|
|
|
547
547
|
|
|
@@ -670,14 +670,14 @@ To search with regular expressions, single quote the string and surround with sl
|
|
|
670
670
|
===== Options
|
|
671
671
|
===== --after DATE_STRING
|
|
672
672
|
|
|
673
|
-
|
|
673
|
+
Search entries newer than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day.
|
|
674
674
|
|
|
675
675
|
[Default Value] None
|
|
676
676
|
|
|
677
677
|
|
|
678
678
|
===== --before DATE_STRING
|
|
679
679
|
|
|
680
|
-
|
|
680
|
+
Search entries older than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day.
|
|
681
681
|
|
|
682
682
|
[Default Value] None
|
|
683
683
|
|
|
@@ -690,6 +690,18 @@ Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart
|
|
|
690
690
|
[Must Match] (?-mix:^[csi])
|
|
691
691
|
|
|
692
692
|
|
|
693
|
+
===== --from DATE_OR_RANGE
|
|
694
|
+
|
|
695
|
+
Date range to show, or a single day to filter date on.
|
|
696
|
+
Date range argument should be quoted. Date specifications can be natural language.
|
|
697
|
+
To specify a range, use "to" or "through": `doing search --from "monday 8am to friday 5pm"`.
|
|
698
|
+
|
|
699
|
+
If values are only time(s) (6am to noon) all dates will be included, but entries will be filtered
|
|
700
|
+
by time of day.
|
|
701
|
+
|
|
702
|
+
[Default Value] None
|
|
703
|
+
|
|
704
|
+
|
|
693
705
|
===== -o|--output FORMAT
|
|
694
706
|
|
|
695
707
|
Output to export format (csv|doing|html|markdown|say|taskpaper|template|timeline|wiki)
|
|
@@ -891,7 +903,7 @@ Tag filter, combine multiple tags with a comma.
|
|
|
891
903
|
|
|
892
904
|
|
|
893
905
|
===== -e|--editor
|
|
894
|
-
Edit entry with
|
|
906
|
+
Edit entry with emacs -nw
|
|
895
907
|
|
|
896
908
|
|
|
897
909
|
|
|
@@ -925,7 +937,7 @@ Note
|
|
|
925
937
|
|
|
926
938
|
|
|
927
939
|
===== -e|--editor
|
|
928
|
-
Edit entry with
|
|
940
|
+
Edit entry with emacs -nw
|
|
929
941
|
|
|
930
942
|
|
|
931
943
|
|
|
@@ -1047,7 +1059,7 @@ Archive previous @meanwhile entry
|
|
|
1047
1059
|
|
|
1048
1060
|
|
|
1049
1061
|
===== -e|--editor
|
|
1050
|
-
Edit entry with
|
|
1062
|
+
Edit entry with emacs -nw
|
|
1051
1063
|
|
|
1052
1064
|
|
|
1053
1065
|
|
|
@@ -1098,7 +1110,7 @@ Add/remove note from last entry matching tag
|
|
|
1098
1110
|
|
|
1099
1111
|
|
|
1100
1112
|
===== -e|--editor
|
|
1101
|
-
Edit entry with
|
|
1113
|
+
Edit entry with emacs -nw
|
|
1102
1114
|
|
|
1103
1115
|
|
|
1104
1116
|
|
|
@@ -1129,7 +1141,7 @@ Record what you're starting now, or backdate the start time using natural langua
|
|
|
1129
1141
|
|
|
1130
1142
|
A parenthetical at the end of the entry will be converted to a note.
|
|
1131
1143
|
|
|
1132
|
-
Run with no argument to create a new entry using
|
|
1144
|
+
Run with no argument to create a new entry using emacs -nw.
|
|
1133
1145
|
===== Options
|
|
1134
1146
|
===== -b|--back|--started DATE_STRING
|
|
1135
1147
|
|
|
@@ -1153,7 +1165,7 @@ Section
|
|
|
1153
1165
|
|
|
1154
1166
|
|
|
1155
1167
|
===== -e|--editor
|
|
1156
|
-
Edit entry with
|
|
1168
|
+
Edit entry with emacs -nw
|
|
1157
1169
|
|
|
1158
1170
|
|
|
1159
1171
|
|
|
@@ -1433,6 +1445,20 @@ Multiple selections are allowed, hit tab to add the highlighted entry to the
|
|
|
1433
1445
|
selection, and use ctrl-a to select all visible items. Return processes the
|
|
1434
1446
|
selected entries.
|
|
1435
1447
|
===== Options
|
|
1448
|
+
===== --after DATE_STRING
|
|
1449
|
+
|
|
1450
|
+
Select from entries newer than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day.
|
|
1451
|
+
|
|
1452
|
+
[Default Value] None
|
|
1453
|
+
|
|
1454
|
+
|
|
1455
|
+
===== --before DATE_STRING
|
|
1456
|
+
|
|
1457
|
+
Select from entries older than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day.
|
|
1458
|
+
|
|
1459
|
+
[Default Value] None
|
|
1460
|
+
|
|
1461
|
+
|
|
1436
1462
|
===== --case TYPE
|
|
1437
1463
|
|
|
1438
1464
|
Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]
|
|
@@ -1441,6 +1467,18 @@ Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart
|
|
|
1441
1467
|
[Must Match] (?-mix:^[csi])
|
|
1442
1468
|
|
|
1443
1469
|
|
|
1470
|
+
===== --from DATE_OR_RANGE
|
|
1471
|
+
|
|
1472
|
+
Date range to show, or a single day to filter date on.
|
|
1473
|
+
Date range argument should be quoted. Date specifications can be natural language.
|
|
1474
|
+
To specify a range, use "to" or "through": `doing select --from "monday 8am to friday 5pm"`.
|
|
1475
|
+
|
|
1476
|
+
If values are only time(s) (6am to noon) all dates will be included, but entries will be filtered
|
|
1477
|
+
by time of day.
|
|
1478
|
+
|
|
1479
|
+
[Default Value] None
|
|
1480
|
+
|
|
1481
|
+
|
|
1444
1482
|
===== -m|--move SECTION
|
|
1445
1483
|
|
|
1446
1484
|
Move selected items to section
|
|
@@ -1558,7 +1596,7 @@ Age (oldest|newest)
|
|
|
1558
1596
|
|
|
1559
1597
|
===== --after DATE_STRING
|
|
1560
1598
|
|
|
1561
|
-
|
|
1599
|
+
Show entries newer than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day.
|
|
1562
1600
|
|
|
1563
1601
|
[Default Value] None
|
|
1564
1602
|
|
|
@@ -1573,7 +1611,7 @@ Tag boolean (AND,OR,NOT)
|
|
|
1573
1611
|
|
|
1574
1612
|
===== --before DATE_STRING
|
|
1575
1613
|
|
|
1576
|
-
|
|
1614
|
+
Show entries older than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day.
|
|
1577
1615
|
|
|
1578
1616
|
[Default Value] None
|
|
1579
1617
|
|
|
@@ -1593,11 +1631,14 @@ Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart
|
|
|
1593
1631
|
[Must Match] (?-mix:^[csi])
|
|
1594
1632
|
|
|
1595
1633
|
|
|
1596
|
-
=====
|
|
1634
|
+
===== --from DATE_OR_RANGE
|
|
1597
1635
|
|
|
1598
1636
|
Date range to show, or a single day to filter date on.
|
|
1599
|
-
|
|
1600
|
-
|
|
1637
|
+
Date range argument should be quoted. Date specifications can be natural language.
|
|
1638
|
+
To specify a range, use "to" or "through": `doing show --from "monday 8am to friday 5pm"`.
|
|
1639
|
+
|
|
1640
|
+
If values are only time(s) (6am to noon) all dates will be included, but entries will be filtered
|
|
1641
|
+
by time of day.
|
|
1601
1642
|
|
|
1602
1643
|
[Default Value] None
|
|
1603
1644
|
|
|
@@ -1869,6 +1910,13 @@ View entries before specified time (e.g. 8am, 12:30pm, 15:00)
|
|
|
1869
1910
|
[Default Value] None
|
|
1870
1911
|
|
|
1871
1912
|
|
|
1913
|
+
===== --from DATE_OR_RANGE
|
|
1914
|
+
|
|
1915
|
+
Time range to show `doing today --from "12pm to 4pm"`
|
|
1916
|
+
|
|
1917
|
+
[Default Value] None
|
|
1918
|
+
|
|
1919
|
+
|
|
1872
1920
|
===== -o|--output FORMAT
|
|
1873
1921
|
|
|
1874
1922
|
Output to export format (csv|doing|html|markdown|say|taskpaper|template|timeline|wiki)
|
|
@@ -1920,7 +1968,7 @@ Command line options override view configuration
|
|
|
1920
1968
|
===== Options
|
|
1921
1969
|
===== --after DATE_STRING
|
|
1922
1970
|
|
|
1923
|
-
View entries newer than date
|
|
1971
|
+
View entries newer than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day.
|
|
1924
1972
|
|
|
1925
1973
|
[Default Value] None
|
|
1926
1974
|
|
|
@@ -1935,7 +1983,7 @@ Tag boolean (AND,OR,NOT)
|
|
|
1935
1983
|
|
|
1936
1984
|
===== --before DATE_STRING
|
|
1937
1985
|
|
|
1938
|
-
View entries older than date
|
|
1986
|
+
View entries older than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day.
|
|
1939
1987
|
|
|
1940
1988
|
[Default Value] None
|
|
1941
1989
|
|
|
@@ -1956,6 +2004,18 @@ Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart
|
|
|
1956
2004
|
[Must Match] (?-mix:^[csi])
|
|
1957
2005
|
|
|
1958
2006
|
|
|
2007
|
+
===== --from DATE_OR_RANGE
|
|
2008
|
+
|
|
2009
|
+
Date range to show, or a single day to filter date on.
|
|
2010
|
+
Date range argument should be quoted. Date specifications can be natural language.
|
|
2011
|
+
To specify a range, use "to" or "through": `doing view --from "monday 8am to friday 5pm" view_name`.
|
|
2012
|
+
|
|
2013
|
+
If values are only time(s) (6am to noon) all dates will be included, but entries will be filtered
|
|
2014
|
+
by time of day.
|
|
2015
|
+
|
|
2016
|
+
[Default Value] None
|
|
2017
|
+
|
|
2018
|
+
|
|
1959
2019
|
===== -o|--output FORMAT
|
|
1960
2020
|
|
|
1961
2021
|
Output to export format (csv|doing|html|markdown|say|taskpaper|template|timeline|wiki)
|
|
@@ -2126,6 +2186,13 @@ View entries before specified time (e.g. 8am, 12:30pm, 15:00)
|
|
|
2126
2186
|
[Default Value] None
|
|
2127
2187
|
|
|
2128
2188
|
|
|
2189
|
+
===== --from TIME_RANGE
|
|
2190
|
+
|
|
2191
|
+
Time range to show, e.g. `doing yesterday --from "1am to 8am"`
|
|
2192
|
+
|
|
2193
|
+
[Default Value] None
|
|
2194
|
+
|
|
2195
|
+
|
|
2129
2196
|
===== -o|--output FORMAT
|
|
2130
2197
|
|
|
2131
2198
|
Output to export format (csv|doing|html|markdown|say|taskpaper|template|timeline|wiki)
|
data/lib/completion/doing.bash
CHANGED
|
@@ -101,9 +101,9 @@ _doing_finish() {
|
|
|
101
101
|
_doing_grep() {
|
|
102
102
|
|
|
103
103
|
if [[ "$token" == --* ]]; then
|
|
104
|
-
COMPREPLY=( $( compgen -W '--after --before --case --interactive --not --output --only_timed --section --times --tag_sort --totals --exact' -- $token ) )
|
|
104
|
+
COMPREPLY=( $( compgen -W '--after --before --case --from --interactive --not --output --only_timed --section --times --tag_sort --totals --exact' -- $token ) )
|
|
105
105
|
elif [[ "$token" == -* ]]; then
|
|
106
|
-
COMPREPLY=( $( compgen -W '-i -o -s -t -x --after --before --case --interactive --not --output --only_timed --section --times --tag_sort --totals --exact' -- $token ) )
|
|
106
|
+
COMPREPLY=( $( compgen -W '-i -o -s -t -x --after --before --case --from --interactive --not --output --only_timed --section --times --tag_sort --totals --exact' -- $token ) )
|
|
107
107
|
|
|
108
108
|
fi
|
|
109
109
|
}
|
|
@@ -261,9 +261,9 @@ _doing_sections() {
|
|
|
261
261
|
_doing_select() {
|
|
262
262
|
|
|
263
263
|
if [[ "$token" == --* ]]; then
|
|
264
|
-
COMPREPLY=( $( compgen -W '--archive --resume --cancel --case --delete --editor --finish --flag --force --move --menu --not --output --search --remove --section --save_to --tag --exact' -- $token ) )
|
|
264
|
+
COMPREPLY=( $( compgen -W '--archive --after --resume --before --cancel --case --delete --editor --finish --flag --force --from --move --menu --not --output --search --remove --section --save_to --tag --exact' -- $token ) )
|
|
265
265
|
elif [[ "$token" == -* ]]; then
|
|
266
|
-
COMPREPLY=( $( compgen -W '-a -c -d -e -f -m -o -r -s -t -x --archive --resume --cancel --case --delete --editor --finish --flag --force --move --menu --not --output --search --remove --section --save_to --tag --exact' -- $token ) )
|
|
266
|
+
COMPREPLY=( $( compgen -W '-a -c -d -e -f -m -o -r -s -t -x --archive --after --resume --before --cancel --case --delete --editor --finish --flag --force --from --move --menu --not --output --search --remove --section --save_to --tag --exact' -- $token ) )
|
|
267
267
|
|
|
268
268
|
fi
|
|
269
269
|
}
|
|
@@ -278,7 +278,7 @@ IFS="$OLD_IFS"
|
|
|
278
278
|
if [[ "$token" == --* ]]; then
|
|
279
279
|
COMPREPLY=( $( compgen -W '--age --after --bool --before --count --case --from --interactive --not --output --only_timed --sort --search --times --tag --tag_order --tag_sort --totals --exact' -- $token ) )
|
|
280
280
|
elif [[ "$token" == -* ]]; then
|
|
281
|
-
COMPREPLY=( $( compgen -W '-a -b -c -
|
|
281
|
+
COMPREPLY=( $( compgen -W '-a -b -c -i -o -s -t -x --age --after --bool --before --count --case --from --interactive --not --output --only_timed --sort --search --times --tag --tag_order --tag_sort --totals --exact' -- $token ) )
|
|
282
282
|
else
|
|
283
283
|
local nocasematchWasOff=0
|
|
284
284
|
shopt nocasematch >/dev/null || nocasematchWasOff=1
|
|
@@ -331,9 +331,9 @@ _doing_template() {
|
|
|
331
331
|
_doing_today() {
|
|
332
332
|
|
|
333
333
|
if [[ "$token" == --* ]]; then
|
|
334
|
-
COMPREPLY=( $( compgen -W '--after --before --output --section --times --tag_sort --totals' -- $token ) )
|
|
334
|
+
COMPREPLY=( $( compgen -W '--after --before --from --output --section --times --tag_sort --totals' -- $token ) )
|
|
335
335
|
elif [[ "$token" == -* ]]; then
|
|
336
|
-
COMPREPLY=( $( compgen -W '-o -s -t --after --before --output --section --times --tag_sort --totals' -- $token ) )
|
|
336
|
+
COMPREPLY=( $( compgen -W '-o -s -t --after --before --from --output --section --times --tag_sort --totals' -- $token ) )
|
|
337
337
|
|
|
338
338
|
fi
|
|
339
339
|
}
|
|
@@ -356,9 +356,9 @@ local words=$(doing views)
|
|
|
356
356
|
IFS="$OLD_IFS"
|
|
357
357
|
|
|
358
358
|
if [[ "$token" == --* ]]; then
|
|
359
|
-
COMPREPLY=( $( compgen -W '--after --bool --before --count --case --color --interactive --not --output --only_timed --section --search --times --tag --tag_order --tag_sort --totals --exact' -- $token ) )
|
|
359
|
+
COMPREPLY=( $( compgen -W '--after --bool --before --count --case --color --from --interactive --not --output --only_timed --section --search --times --tag --tag_order --tag_sort --totals --exact' -- $token ) )
|
|
360
360
|
elif [[ "$token" == -* ]]; then
|
|
361
|
-
COMPREPLY=( $( compgen -W '-b -c -i -o -s -t -x --after --bool --before --count --case --color --interactive --not --output --only_timed --section --search --times --tag --tag_order --tag_sort --totals --exact' -- $token ) )
|
|
361
|
+
COMPREPLY=( $( compgen -W '-b -c -i -o -s -t -x --after --bool --before --count --case --color --from --interactive --not --output --only_timed --section --search --times --tag --tag_order --tag_sort --totals --exact' -- $token ) )
|
|
362
362
|
else
|
|
363
363
|
local nocasematchWasOff=0
|
|
364
364
|
shopt nocasematch >/dev/null || nocasematchWasOff=1
|
|
@@ -401,9 +401,9 @@ _doing_wiki() {
|
|
|
401
401
|
_doing_yesterday() {
|
|
402
402
|
|
|
403
403
|
if [[ "$token" == --* ]]; then
|
|
404
|
-
COMPREPLY=( $( compgen -W '--after --before --output --section --times --tag_order --tag_sort --totals' -- $token ) )
|
|
404
|
+
COMPREPLY=( $( compgen -W '--after --before --from --output --section --times --tag_order --tag_sort --totals' -- $token ) )
|
|
405
405
|
elif [[ "$token" == -* ]]; then
|
|
406
|
-
COMPREPLY=( $( compgen -W '-o -s -t --after --before --output --section --times --tag_order --tag_sort --totals' -- $token ) )
|
|
406
|
+
COMPREPLY=( $( compgen -W '-o -s -t --after --before --from --output --section --times --tag_order --tag_sort --totals' -- $token ) )
|
|
407
407
|
|
|
408
408
|
fi
|
|
409
409
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doing
|
|
4
|
+
# Chronify methods for strings
|
|
5
|
+
class ::String
|
|
6
|
+
##
|
|
7
|
+
## Converts input string into a Time object when input
|
|
8
|
+
## takes on the following formats:
|
|
9
|
+
## - interval format e.g. '1d2h30m', '45m'
|
|
10
|
+
## etc.
|
|
11
|
+
## - a semantic phrase e.g. 'yesterday
|
|
12
|
+
## 5:30pm'
|
|
13
|
+
## - a strftime e.g. '2016-03-15 15:32:04
|
|
14
|
+
## PDT'
|
|
15
|
+
##
|
|
16
|
+
## @param options Additional options
|
|
17
|
+
##
|
|
18
|
+
## @option options :future [Boolean] assume future date
|
|
19
|
+
## (default: false)
|
|
20
|
+
##
|
|
21
|
+
## @option options :guess [Symbol] :begin or :end to
|
|
22
|
+
## assume beginning or end of
|
|
23
|
+
## arbitrary time range
|
|
24
|
+
##
|
|
25
|
+
## @return [DateTime] result
|
|
26
|
+
##
|
|
27
|
+
def chronify(**options)
|
|
28
|
+
now = Time.now
|
|
29
|
+
raise InvalidTimeExpression, "Invalid time expression #{inspect}" if to_s.strip == ''
|
|
30
|
+
|
|
31
|
+
secs_ago = if match(/^(\d+)$/)
|
|
32
|
+
# plain number, assume minutes
|
|
33
|
+
Regexp.last_match(1).to_i * 60
|
|
34
|
+
elsif (m = match(/^(?:(?<day>\d+)d)?(?:(?<hour>\d+)h)?(?:(?<min>\d+)m)?$/i))
|
|
35
|
+
# day/hour/minute format e.g. 1d2h30m
|
|
36
|
+
[[m['day'], 24 * 3600],
|
|
37
|
+
[m['hour'], 3600],
|
|
38
|
+
[m['min'], 60]].map { |qty, secs| qty ? (qty.to_i * secs) : 0 }.reduce(0, :+)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
if secs_ago
|
|
42
|
+
now - secs_ago
|
|
43
|
+
else
|
|
44
|
+
Chronic.parse(self, { guess: options.fetch(:guess, :begin), context: options.fetch(:future, false) ? :future : :past, ambiguous_time_range: 8 })
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
##
|
|
49
|
+
## Converts simple strings into seconds that can be
|
|
50
|
+
## added to a Time object
|
|
51
|
+
##
|
|
52
|
+
## Input string can be HH:MM or XX[dhm][[XXhm][XXm]]
|
|
53
|
+
## (1d2h30m, 45m, 1.5d, 1h20m, etc.)
|
|
54
|
+
##
|
|
55
|
+
## @return [Integer] seconds
|
|
56
|
+
##
|
|
57
|
+
def chronify_qty
|
|
58
|
+
minutes = 0
|
|
59
|
+
case self.strip
|
|
60
|
+
when /^(\d+):(\d\d)$/
|
|
61
|
+
minutes += Regexp.last_match(1).to_i * 60
|
|
62
|
+
minutes += Regexp.last_match(2).to_i
|
|
63
|
+
when /^(\d+(?:\.\d+)?)([hmd])?$/
|
|
64
|
+
amt = Regexp.last_match(1)
|
|
65
|
+
type = Regexp.last_match(2).nil? ? 'm' : Regexp.last_match(2)
|
|
66
|
+
|
|
67
|
+
minutes = case type.downcase
|
|
68
|
+
when 'm'
|
|
69
|
+
amt.to_i
|
|
70
|
+
when 'h'
|
|
71
|
+
(amt.to_f * 60).round
|
|
72
|
+
when 'd'
|
|
73
|
+
(amt.to_f * 60 * 24).round
|
|
74
|
+
else
|
|
75
|
+
minutes
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
minutes * 60
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
data/lib/doing/version.rb
CHANGED
data/lib/doing/wwid.rb
CHANGED
|
@@ -190,7 +190,7 @@ module Doing
|
|
|
190
190
|
m = Regexp.last_match
|
|
191
191
|
t = m['tag']
|
|
192
192
|
d = m['date']
|
|
193
|
-
parsed_date = d =~ date_rx ? Time.parse(d) : chronify(
|
|
193
|
+
parsed_date = d =~ date_rx ? Time.parse(d) : d.chronify(guess: :begin)
|
|
194
194
|
parsed_date.nil? ? m[0] : "@#{t}(#{parsed_date.strftime('%F %R')})"
|
|
195
195
|
end
|
|
196
196
|
|
|
@@ -200,7 +200,7 @@ module Doing
|
|
|
200
200
|
date = if d =~ iso_rx
|
|
201
201
|
Time.parse(d)
|
|
202
202
|
else
|
|
203
|
-
chronify(
|
|
203
|
+
d.chronify(guess: :begin)
|
|
204
204
|
end
|
|
205
205
|
title.sub!(date_rx, '').strip!
|
|
206
206
|
end
|
|
@@ -222,71 +222,6 @@ module Doing
|
|
|
222
222
|
[date, title, note]
|
|
223
223
|
end
|
|
224
224
|
|
|
225
|
-
##
|
|
226
|
-
## Converts input string into a Time object when input takes on the
|
|
227
|
-
## following formats:
|
|
228
|
-
## - interval format e.g. '1d2h30m', '45m' etc.
|
|
229
|
-
## - a semantic phrase e.g. 'yesterday 5:30pm'
|
|
230
|
-
## - a strftime e.g. '2016-03-15 15:32:04 PDT'
|
|
231
|
-
##
|
|
232
|
-
## @param input [String] String to chronify
|
|
233
|
-
##
|
|
234
|
-
## @return [DateTime] result
|
|
235
|
-
##
|
|
236
|
-
def chronify(input, future: false, guess: :begin)
|
|
237
|
-
now = Time.now
|
|
238
|
-
raise InvalidTimeExpression, "Invalid time expression #{input.inspect}" if input.to_s.strip == ''
|
|
239
|
-
|
|
240
|
-
secs_ago = if input.match(/^(\d+)$/)
|
|
241
|
-
# plain number, assume minutes
|
|
242
|
-
Regexp.last_match(1).to_i * 60
|
|
243
|
-
elsif (m = input.match(/^(?:(?<day>\d+)d)?(?:(?<hour>\d+)h)?(?:(?<min>\d+)m)?$/i))
|
|
244
|
-
# day/hour/minute format e.g. 1d2h30m
|
|
245
|
-
[[m['day'], 24 * 3600],
|
|
246
|
-
[m['hour'], 3600],
|
|
247
|
-
[m['min'], 60]].map { |qty, secs| qty ? (qty.to_i * secs) : 0 }.reduce(0, :+)
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
if secs_ago
|
|
251
|
-
now - secs_ago
|
|
252
|
-
else
|
|
253
|
-
Chronic.parse(input, { guess: guess, context: future ? :future : :past, ambiguous_time_range: 8 })
|
|
254
|
-
end
|
|
255
|
-
end
|
|
256
|
-
|
|
257
|
-
##
|
|
258
|
-
## Converts simple strings into seconds that can be added to a Time
|
|
259
|
-
## object
|
|
260
|
-
##
|
|
261
|
-
## @param qty [String] HH:MM or XX[dhm][[XXhm][XXm]] (1d2h30m, 45m,
|
|
262
|
-
## 1.5d, 1h20m, etc.)
|
|
263
|
-
##
|
|
264
|
-
## @return [Integer] seconds
|
|
265
|
-
##
|
|
266
|
-
def chronify_qty(qty)
|
|
267
|
-
minutes = 0
|
|
268
|
-
case qty.strip
|
|
269
|
-
when /^(\d+):(\d\d)$/
|
|
270
|
-
minutes += Regexp.last_match(1).to_i * 60
|
|
271
|
-
minutes += Regexp.last_match(2).to_i
|
|
272
|
-
when /^(\d+(?:\.\d+)?)([hmd])?$/
|
|
273
|
-
amt = Regexp.last_match(1)
|
|
274
|
-
type = Regexp.last_match(2).nil? ? 'm' : Regexp.last_match(2)
|
|
275
|
-
|
|
276
|
-
minutes = case type.downcase
|
|
277
|
-
when 'm'
|
|
278
|
-
amt.to_i
|
|
279
|
-
when 'h'
|
|
280
|
-
(amt.to_f * 60).round
|
|
281
|
-
when 'd'
|
|
282
|
-
(amt.to_f * 60 * 24).round
|
|
283
|
-
else
|
|
284
|
-
minutes
|
|
285
|
-
end
|
|
286
|
-
end
|
|
287
|
-
minutes * 60
|
|
288
|
-
end
|
|
289
|
-
|
|
290
225
|
##
|
|
291
226
|
## List sections
|
|
292
227
|
##
|
|
@@ -661,12 +596,55 @@ module Doing
|
|
|
661
596
|
## @option opt [String] :age ('old' or 'new')
|
|
662
597
|
##
|
|
663
598
|
def filter_items(items = Items.new, opt: {})
|
|
599
|
+
time_rx = /^(\d{1,2}+(:\d{1,2}+)?( *(am|pm))?|midnight|noon)$/
|
|
600
|
+
|
|
664
601
|
if items.nil? || items.empty?
|
|
665
602
|
section = opt[:section] ? guess_section(opt[:section]) : 'All'
|
|
666
|
-
|
|
667
603
|
items = section =~ /^all$/i ? @content.dup : @content.in_section(section)
|
|
668
604
|
end
|
|
669
605
|
|
|
606
|
+
opt[:time_filter] = [nil, nil]
|
|
607
|
+
if opt[:from] && !opt[:date_filter]
|
|
608
|
+
date_string = opt[:from]
|
|
609
|
+
case date_string
|
|
610
|
+
when / (to|through|thru|(un)?til|-+) /
|
|
611
|
+
dates = date_string.split(/ (?:to|through|thru|(?:un)?til|-+) /)
|
|
612
|
+
if dates[0].strip =~ time_rx && dates[-1].strip =~ time_rx
|
|
613
|
+
time_start = dates[0].strip
|
|
614
|
+
time_end = dates[-1].strip
|
|
615
|
+
else
|
|
616
|
+
start = dates[0].chronify(guess: :begin)
|
|
617
|
+
finish = dates[-1].chronify(guess: :end)
|
|
618
|
+
end
|
|
619
|
+
when time_rx
|
|
620
|
+
time_start = date_string
|
|
621
|
+
time_end = nil
|
|
622
|
+
else
|
|
623
|
+
start = date_string.chronify(guess: :begin)
|
|
624
|
+
finish = false
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
if time_start
|
|
628
|
+
opt[:time_filter] = [time_start, time_end]
|
|
629
|
+
Doing.logger.debug('Parser:', "--from string interpreted as time span, from #{time_start ? time_start : '12am'} to #{time_end ? time_end : '11:59pm'}")
|
|
630
|
+
else
|
|
631
|
+
raise InvalidTimeExpression, 'Unrecognized date string' unless start
|
|
632
|
+
|
|
633
|
+
opt[:date_filter] = [start, finish]
|
|
634
|
+
Doing.logger.debug('Parser:', "--from string interpreted as #{start.strftime('%F %R')} -- #{finish ? finish.strftime('%F %R') : 'now'}")
|
|
635
|
+
end
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
if opt[:before] =~ time_rx
|
|
639
|
+
opt[:time_filter][1] = opt[:before]
|
|
640
|
+
opt[:before] = nil
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
if opt[:after] =~ time_rx
|
|
644
|
+
opt[:time_filter][0] = opt[:after]
|
|
645
|
+
opt[:after] = nil
|
|
646
|
+
end
|
|
647
|
+
|
|
670
648
|
items.sort_by! { |item| [item.date, item.title.downcase] }.reverse
|
|
671
649
|
|
|
672
650
|
filtered_items = items.select do |item|
|
|
@@ -708,6 +686,26 @@ module Doing
|
|
|
708
686
|
keep = opt[:not] ? !keep : keep
|
|
709
687
|
end
|
|
710
688
|
|
|
689
|
+
if keep && opt[:time_filter][0] || opt[:time_filter][1]
|
|
690
|
+
start_string = if opt[:time_filter][0].nil?
|
|
691
|
+
"#{item.date.strftime('%Y-%m-%d')} 12am"
|
|
692
|
+
else
|
|
693
|
+
"#{item.date.strftime('%Y-%m-%d')} #{opt[:time_filter][0]}"
|
|
694
|
+
end
|
|
695
|
+
start_time = start_string.chronify(guess: :begin)
|
|
696
|
+
|
|
697
|
+
end_string = if opt[:time_filter][1].nil?
|
|
698
|
+
"#{item.date.next_day.strftime('%Y-%m-%d')} 12am"
|
|
699
|
+
else
|
|
700
|
+
"#{item.date.strftime('%Y-%m-%d')} #{opt[:time_filter][1]}"
|
|
701
|
+
end
|
|
702
|
+
end_time = end_string.chronify(guess: :end)
|
|
703
|
+
|
|
704
|
+
in_time_range = item.date >= start_time && item.date <= end_time
|
|
705
|
+
keep = false unless in_time_range
|
|
706
|
+
keep = opt[:not] ? !keep : keep
|
|
707
|
+
end
|
|
708
|
+
|
|
711
709
|
keep = false if keep && opt[:only_timed] && !item.interval
|
|
712
710
|
|
|
713
711
|
if keep && opt[:tag_filter] && !opt[:tag_filter]['tags'].empty?
|
|
@@ -717,14 +715,22 @@ module Doing
|
|
|
717
715
|
|
|
718
716
|
if keep && opt[:before]
|
|
719
717
|
time_string = opt[:before]
|
|
720
|
-
|
|
718
|
+
if time_string =~ time_rx
|
|
719
|
+
cutoff = "#{item.date.strftime('%Y-%m-%d')} #{time_string}".chronify(guess: :begin)
|
|
720
|
+
else
|
|
721
|
+
cutoff = time_string.chronify(guess: :begin)
|
|
722
|
+
end
|
|
721
723
|
keep = cutoff && item.date <= cutoff
|
|
722
724
|
keep = opt[:not] ? !keep : keep
|
|
723
725
|
end
|
|
724
726
|
|
|
725
727
|
if keep && opt[:after]
|
|
726
728
|
time_string = opt[:after]
|
|
727
|
-
|
|
729
|
+
if time_string =~ time_rx
|
|
730
|
+
cutoff = "#{item.date.strftime('%Y-%m-%d')} #{time_string}".chronify(guess: :end)
|
|
731
|
+
else
|
|
732
|
+
cutoff = time_string.chronify(guess: :end)
|
|
733
|
+
end
|
|
728
734
|
keep = cutoff && item.date >= cutoff
|
|
729
735
|
keep = opt[:not] ? !keep : keep
|
|
730
736
|
end
|
|
@@ -760,7 +766,7 @@ module Doing
|
|
|
760
766
|
## Options hash is shared with #filter_items and #act_on
|
|
761
767
|
##
|
|
762
768
|
def interactive(opt = {})
|
|
763
|
-
section = opt[:section] ? guess_section(opt[:section]) : 'All'
|
|
769
|
+
opt[:section] = opt[:section] ? guess_section(opt[:section]) : 'All'
|
|
764
770
|
|
|
765
771
|
search = nil
|
|
766
772
|
|
|
@@ -774,9 +780,12 @@ module Doing
|
|
|
774
780
|
opt[:query] = "!#{opt[:query]}" if opt[:not]
|
|
775
781
|
opt[:multiple] = true
|
|
776
782
|
opt[:show_if_single] = true
|
|
777
|
-
|
|
783
|
+
filter_options = %i[after before case date_filter from fuzzy not search section].each_with_object({}) {
|
|
784
|
+
|k, hsh| hsh[k] = opt[k]
|
|
785
|
+
}
|
|
786
|
+
items = filter_items(Items.new, opt: filter_options)
|
|
778
787
|
|
|
779
|
-
selection = Prompt.choose_from_items(items, include_section: section =~ /^all$/i, **opt)
|
|
788
|
+
selection = Prompt.choose_from_items(items, include_section: opt[:section] =~ /^all$/i, **opt)
|
|
780
789
|
|
|
781
790
|
raise NoResults, 'no items selected' if selection.nil? || selection.empty?
|
|
782
791
|
|
|
@@ -1336,7 +1345,7 @@ module Doing
|
|
|
1336
1345
|
break if counter >= max
|
|
1337
1346
|
if opt[:before]
|
|
1338
1347
|
time_string = opt[:before]
|
|
1339
|
-
cutoff = chronify(
|
|
1348
|
+
cutoff = time_string.chronify(guess: :begin)
|
|
1340
1349
|
end
|
|
1341
1350
|
|
|
1342
1351
|
unless ((!tags.empty? && !item.tags?(tags, bool)) || (opt[:search] && !item.search(opt[:search].to_s)) || (opt[:before] && item.date >= cutoff))
|
|
@@ -1524,10 +1533,12 @@ module Doing
|
|
|
1524
1533
|
'order' => @config['order'] || 'asc',
|
|
1525
1534
|
'tags_color' => @config['tags_color']
|
|
1526
1535
|
})
|
|
1536
|
+
|
|
1527
1537
|
options = {
|
|
1528
1538
|
after: opt[:after],
|
|
1529
1539
|
before: opt[:before],
|
|
1530
1540
|
count: 0,
|
|
1541
|
+
from: opt[:from],
|
|
1531
1542
|
format: cfg['date_format'],
|
|
1532
1543
|
order: cfg['order'] || 'asc',
|
|
1533
1544
|
output: output,
|
|
@@ -1584,6 +1595,7 @@ module Doing
|
|
|
1584
1595
|
after: opt[:after],
|
|
1585
1596
|
before: opt[:before],
|
|
1586
1597
|
count: 0,
|
|
1598
|
+
from: opt[:from],
|
|
1587
1599
|
order: opt[:order],
|
|
1588
1600
|
output: output,
|
|
1589
1601
|
section: section,
|
|
@@ -2044,7 +2056,7 @@ EOS
|
|
|
2044
2056
|
break if counter >= max
|
|
2045
2057
|
if opt[:before]
|
|
2046
2058
|
time_string = opt[:before]
|
|
2047
|
-
cutoff = chronify(
|
|
2059
|
+
cutoff = time_string.chronify(guess: :begin)
|
|
2048
2060
|
end
|
|
2049
2061
|
|
|
2050
2062
|
if (item.section.downcase != section.downcase && section != /^all$/i) || item.section.downcase == destination.downcase
|
data/lib/doing.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: doing
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.1.
|
|
4
|
+
version: 2.1.1pre
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brett Terpstra
|
|
@@ -444,6 +444,7 @@ files:
|
|
|
444
444
|
- lib/doing/prompt.rb
|
|
445
445
|
- lib/doing/section.rb
|
|
446
446
|
- lib/doing/string.rb
|
|
447
|
+
- lib/doing/string_chronify.rb
|
|
447
448
|
- lib/doing/symbol.rb
|
|
448
449
|
- lib/doing/time.rb
|
|
449
450
|
- lib/doing/util.rb
|