doing 2.1.40 → 2.1.41
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +1 -1
- data/CHANGELOG.md +22 -0
- data/Gemfile.lock +1 -1
- data/Rakefile +4 -4
- data/bin/commands/changes.rb +1 -1
- data/bin/commands/tag_dir.rb +49 -15
- data/{Dockerfile → docker/Dockerfile} +3 -1
- data/{Dockerfile-2.6 → docker/Dockerfile-2.6} +2 -2
- data/{Dockerfile-2.7 → docker/Dockerfile-2.7} +2 -2
- data/{Dockerfile-3.0 → docker/Dockerfile-3.0} +2 -2
- data/{bash_profile → docker/bash_profile} +0 -0
- data/{inputrc → docker/inputrc} +0 -0
- data/docs/doc/Array.html +84 -2
- data/docs/doc/BooleanTermParser/Clause.html +1 -1
- data/docs/doc/BooleanTermParser/Operator.html +1 -1
- data/docs/doc/BooleanTermParser/Query.html +1 -1
- data/docs/doc/BooleanTermParser/QueryParser.html +1 -1
- data/docs/doc/BooleanTermParser/QueryTransformer.html +1 -1
- data/docs/doc/BooleanTermParser.html +1 -1
- data/docs/doc/Doing/ArrayNestedHash.html +198 -0
- data/docs/doc/Doing/ArrayTags.html +424 -0
- data/docs/doc/Doing/CSVExport.html +266 -0
- data/docs/doc/Doing/CalendarImport.html +232 -0
- data/docs/doc/Doing/Change.html +617 -0
- data/docs/doc/Doing/Changes.html +468 -0
- data/docs/doc/Doing/ChronifyArray.html +347 -0
- data/docs/doc/Doing/ChronifyNumeric.html +271 -0
- data/docs/doc/Doing/ChronifyString.html +682 -0
- data/docs/doc/Doing/Color.html +2 -2
- data/docs/doc/Doing/Completion/BashCompletions.html +445 -0
- data/docs/doc/Doing/Completion/FishCompletions.html +445 -0
- data/docs/doc/Doing/Completion/StringUtils.html +229 -0
- data/docs/doc/Doing/Completion/ZshCompletions.html +445 -0
- data/docs/doc/Doing/Completion.html +17 -3
- data/docs/doc/Doing/Configuration.html +1 -1
- data/docs/doc/Doing/DayOneRenderer.html +383 -0
- data/docs/doc/Doing/DayoneExport.html +290 -0
- data/docs/doc/Doing/DoingImport.html +391 -0
- data/docs/doc/Doing/Entry.html +381 -0
- data/docs/doc/Doing/Errors/DoingNoTraceError.html +1 -1
- data/docs/doc/Doing/Errors/DoingRuntimeError.html +1 -1
- data/docs/doc/Doing/Errors/DoingStandardError.html +1 -1
- data/docs/doc/Doing/Errors/EmptyInput.html +1 -1
- data/docs/doc/Doing/Errors/HistoryLimitError.html +1 -1
- data/docs/doc/Doing/Errors/InvalidPlugin.html +1 -1
- data/docs/doc/Doing/Errors/MissingBackupFile.html +1 -1
- data/docs/doc/Doing/Errors/NoResults.html +1 -1
- data/docs/doc/Doing/Errors/PluginException.html +1 -1
- data/docs/doc/Doing/Errors/UserCancelled.html +1 -1
- data/docs/doc/Doing/Errors/WrongCommand.html +1 -1
- data/docs/doc/Doing/Errors.html +1 -1
- data/docs/doc/Doing/HTMLExport.html +256 -0
- data/docs/doc/Doing/Hooks.html +1 -1
- data/docs/doc/Doing/Item.html +47 -3
- data/docs/doc/Doing/ItemDates.html +564 -0
- data/docs/doc/Doing/ItemQuery.html +614 -0
- data/docs/doc/Doing/ItemState.html +387 -0
- data/docs/doc/Doing/ItemTags.html +498 -0
- data/docs/doc/Doing/Items.html +460 -11
- data/docs/doc/Doing/JSONExport.html +222 -0
- data/docs/doc/Doing/Logger.html +1 -1
- data/docs/doc/Doing/MarkdownExport.html +266 -0
- data/docs/doc/Doing/MarkdownRenderer.html +383 -0
- data/docs/doc/Doing/Note.html +16 -3
- data/docs/doc/Doing/Pager.html +1 -1
- data/docs/doc/Doing/Plugins.html +1 -1
- data/docs/doc/Doing/Prompt.html +31 -682
- data/docs/doc/Doing/PromptChoose.html +484 -0
- data/docs/doc/Doing/PromptFZF.html +391 -0
- data/docs/doc/Doing/PromptInput.html +572 -0
- data/docs/doc/Doing/PromptSTD.html +293 -0
- data/docs/doc/Doing/PromptYN.html +237 -0
- data/docs/doc/Doing/Section.html +58 -2
- data/docs/doc/Doing/StringHighlight.html +533 -0
- data/docs/doc/Doing/StringNormalize.html +929 -0
- data/docs/doc/Doing/StringQuery.html +725 -0
- data/docs/doc/Doing/StringTags.html +884 -0
- data/docs/doc/Doing/StringTransform.html +565 -0
- data/docs/doc/Doing/StringTruncate.html +448 -0
- data/docs/doc/Doing/StringURL.html +409 -0
- data/docs/doc/Doing/SymbolNormalize.html +341 -0
- data/docs/doc/Doing/TaskPaperExport.html +222 -0
- data/docs/doc/Doing/TemplateExport.html +249 -0
- data/docs/doc/Doing/TemplateString.html +101 -2
- data/docs/doc/Doing/TimingImport.html +285 -0
- data/docs/doc/Doing/Types.html +1 -1
- data/docs/doc/Doing/Util/Backup.html +9 -7
- data/docs/doc/Doing/Util.html +2 -2
- data/docs/doc/Doing/Version.html +523 -0
- data/docs/doc/Doing/WWID/WWIDUtil.html +510 -0
- data/docs/doc/Doing/WWID.html +4377 -217
- data/docs/doc/Doing/WWIDDisplay.html +865 -0
- data/docs/doc/Doing/WWIDEditor.html +466 -0
- data/docs/doc/Doing/WWIDFileTools.html +359 -0
- data/docs/doc/Doing/WWIDFilter.html +466 -0
- data/docs/doc/Doing/WWIDGuess.html +299 -0
- data/docs/doc/Doing/WWIDInteractive.html +752 -0
- data/docs/doc/Doing/WWIDModify.html +1078 -0
- data/docs/doc/Doing/WWIDTags.html +302 -0
- data/docs/doc/Doing/WWIDTimers.html +359 -0
- data/docs/doc/Doing/WWIDUtil.html +510 -0
- data/docs/doc/Doing.html +9 -6
- data/docs/doc/FalseClass.html +1 -1
- data/docs/doc/GLI/Commands/Help.html +1 -1
- data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
- data/docs/doc/GLI/Commands.html +1 -1
- data/docs/doc/GLI.html +1 -1
- data/docs/doc/Hash.html +1 -1
- data/docs/doc/Numeric.html +23 -78
- data/docs/doc/Object.html +1 -1
- data/docs/doc/PhraseParser/Operator.html +1 -1
- data/docs/doc/PhraseParser/PhraseClause.html +1 -1
- data/docs/doc/PhraseParser/Query.html +1 -1
- data/docs/doc/PhraseParser/QueryParser.html +1 -1
- data/docs/doc/PhraseParser/QueryTransformer.html +1 -1
- data/docs/doc/PhraseParser/TermClause.html +1 -1
- data/docs/doc/PhraseParser.html +1 -1
- data/docs/doc/Status.html +1 -1
- data/docs/doc/String.html +58 -633
- data/docs/doc/Symbol.html +9 -224
- data/docs/doc/Time.html +119 -13
- data/docs/doc/TrueClass.html +1 -1
- data/docs/doc/_index.html +324 -8
- data/docs/doc/class_list.html +1 -1
- data/docs/doc/file.README.html +1 -1
- data/docs/doc/index.html +1 -1
- data/docs/doc/method_list.html +2326 -542
- data/docs/doc/top-level-namespace.html +2 -2
- data/doing.rdoc +13 -3
- data/lib/completion/_doing.zsh +1 -1
- data/lib/completion/doing.bash +2 -2
- data/lib/completion/doing.fish +3 -1
- data/lib/doing/array/array.rb +16 -12
- data/lib/doing/array/nested_hash.rb +1 -1
- data/lib/doing/array/tags.rb +6 -5
- data/lib/doing/changelog/changelog.rb +6 -0
- data/lib/doing/chronify/array.rb +1 -3
- data/lib/doing/chronify/chronify.rb +12 -0
- data/lib/doing/chronify/numeric.rb +3 -2
- data/lib/doing/chronify/string.rb +1 -1
- data/lib/doing/completion/completion_string.rb +25 -0
- data/lib/doing/completion.rb +1 -1
- data/lib/doing/good.rb +8 -0
- data/lib/doing/item/dates.rb +1 -1
- data/lib/doing/{item.rb → item/item.rb} +10 -5
- data/lib/doing/item/query.rb +1 -1
- data/lib/doing/item/state.rb +1 -1
- data/lib/doing/item/tags.rb +1 -1
- data/lib/doing/items/filter.rb +67 -0
- data/lib/doing/items/items.rb +57 -0
- data/lib/doing/items/modify.rb +36 -0
- data/lib/doing/items/sections.rb +83 -0
- data/lib/doing/items/util.rb +74 -0
- data/lib/doing/normalize.rb +10 -2
- data/lib/doing/plugins/export/markdown_export.rb +4 -2
- data/lib/doing/plugins/import/doing_import.rb +1 -1
- data/lib/doing/prompt/choose.rb +118 -0
- data/lib/doing/prompt/fzf.rb +84 -0
- data/lib/doing/prompt/input.rb +129 -0
- data/lib/doing/prompt/prompt.rb +41 -0
- data/lib/doing/prompt/std.rb +32 -0
- data/lib/doing/prompt/yn.rb +64 -0
- data/lib/doing/section.rb +4 -0
- data/lib/doing/string/highlight.rb +1 -1
- data/lib/doing/string/query.rb +1 -1
- data/lib/doing/string/string.rb +18 -7
- data/lib/doing/string/tags.rb +14 -3
- data/lib/doing/string/transform.rb +1 -1
- data/lib/doing/string/truncate.rb +1 -1
- data/lib/doing/string/url.rb +1 -1
- data/lib/doing/time.rb +19 -1
- data/lib/doing/util_backup.rb +2 -2
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid/display.rb +357 -360
- data/lib/doing/wwid/editor.rb +173 -176
- data/lib/doing/wwid/filetools.rb +156 -159
- data/lib/doing/wwid/filter.rb +191 -183
- data/lib/doing/wwid/guess.rb +58 -60
- data/lib/doing/wwid/interactive.rb +332 -330
- data/lib/doing/wwid/modify.rb +509 -512
- data/lib/doing/wwid/tags.rb +38 -41
- data/lib/doing/wwid/timers.rb +293 -296
- data/lib/doing/{wwid.rb → wwid/wwid.rb} +32 -23
- data/lib/doing/wwid/wwidutil.rb +79 -82
- data/lib/doing.rb +5 -5
- data/lib/helpers/threaded_tests.rb +1 -0
- metadata +76 -14
- data/lib/doing/changelog.rb +0 -6
- data/lib/doing/completion/string.rb +0 -17
- data/lib/doing/items.rb +0 -221
- data/lib/doing/prompt.rb +0 -330
@@ -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="FalseClass.html" title="FalseClass (class)">FalseClass</a></span>, <span class='object_link'><a href="Hash.html" title="Hash (class)">Hash</a></span>, <span class='object_link'><a href="Object.html" title="Object (class)">Object</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>, <span class='object_link'><a href="TrueClass.html" title="TrueClass (class)">TrueClass</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="FalseClass.html" title="FalseClass (class)">FalseClass</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="Object.html" title="Object (class)">Object</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>, <span class='object_link'><a href="TrueClass.html" title="TrueClass (class)">TrueClass</a></span>
|
90
90
|
|
91
91
|
|
92
92
|
</p>
|
@@ -206,7 +206,7 @@
|
|
206
206
|
</div>
|
207
207
|
|
208
208
|
<div id="footer">
|
209
|
-
Generated on
|
209
|
+
Generated on Wed Mar 16 09:42:15 2022 by
|
210
210
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
211
211
|
0.9.27 (ruby-3.0.1).
|
212
212
|
</div>
|
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.41
|
9
9
|
|
10
10
|
=== Global Options
|
11
11
|
=== --config_file arg
|
@@ -439,7 +439,7 @@ Look up a specific version. Specify versions as "MAJ.MIN.PATCH", MIN
|
|
439
439
|
to a version. Wildcards (*?) accepted unless using < or >.
|
440
440
|
|
441
441
|
[Default Value] None
|
442
|
-
[Must Match] (?-mix:^(?:(?:(?:[<>=]+|p(?:rior)|b(?:efore)|o(?:lder)|s(?:ince)|a(?:fter)|n(?:ewer))? *[0-9.*?]
|
442
|
+
[Must Match] (?-mix:^(?:(?:(?:[<>=]+|p(?:rior)|b(?:efore)|o(?:lder)|s(?:ince)|a(?:fter)|n(?:ewer))? *[0-9.*?]{1,10} *)+|(?:[\d.]+ *(?:-|to)+ *[0-9.]{1,10}))$)
|
443
443
|
|
444
444
|
|
445
445
|
===== -s|--search arg
|
@@ -2628,11 +2628,21 @@ Adds default_tags to a .doingrc file in the current directory. Any entry created
|
|
2628
2628
|
subdirectories will be tagged with the default tags. You can modify these any time using the `config set` commnand or
|
2629
2629
|
manually editing the .doingrc file.
|
2630
2630
|
===== Options
|
2631
|
-
=====
|
2631
|
+
===== --clear
|
2632
2632
|
Remove all default_tags from the local .doingrc
|
2633
2633
|
|
2634
2634
|
|
2635
2635
|
|
2636
|
+
===== -e|--editor
|
2637
|
+
Use default editor to edit tag list
|
2638
|
+
|
2639
|
+
|
2640
|
+
|
2641
|
+
===== -r|--remove
|
2642
|
+
Delete tag(s) from the current list
|
2643
|
+
|
2644
|
+
|
2645
|
+
|
2636
2646
|
==== Command: <tt>tags [MAX_COUNT]</tt>
|
2637
2647
|
List all tags in the current Doing file
|
2638
2648
|
|
data/lib/completion/_doing.zsh
CHANGED
@@ -183,7 +183,7 @@ function _doing() {
|
|
183
183
|
args=( {'(--autotag)-a','(-a)--autotag'}"[Autotag entries based on autotag configuration in ~/]" "--bool[Boolean used to combine multiple tags]:BOOLEAN:" {'(--count)-c','(-c)--count'}"[How many recent entries to tag]:COUNT:" "--case[Case sensitivity for search string matching ((c)ase-sensitive]:TYPE:" {'(--date)-d','(-d)--date'}"[Include current date/time with tag]" "--force[Dont ask permission to tag all entries when count is 0t ask permission to tag all entries when count is 0]" {'(--interactive)-i','(-i)--interactive'}"[Select item(s) to tag from a menu of matching entries]" "--not[Tag items that *dont* match search/tag filterst* match search/tag filters]" {'(--remove)-r','(-r)--remove'}"[Remove given tag(s)]" "--regex[Interpret tag string as regular expression]" "--rename[Replace existing tag with tag argument]:ORIG_TAG:" {'(--section)-s','(-s)--section'}"[Section]:SECTION_NAME:" "--search[Filter entries using a search query]:QUERY:" "--tag[Filter entries by tag]:TAG:" {'(--unfinished)-u','(-u)--unfinished'}"[Tag last entry]" {'(--value)-v','(-v)--value'}"[Include a value]:VALUE:" "--val[Perform a tag value query]:QUERY:" {'(--exact)-x','(-x)--exact'}"[Force exact search string matching]" )
|
184
184
|
;;
|
185
185
|
tag_dir)
|
186
|
-
args=( {'(--remove)-r','(-r)--remove'}"[
|
186
|
+
args=( "--clear[Remove all default_tags from the local]" {'(--editor)-e','(-e)--editor'}"[Use default editor to edit tag list]" {'(--remove)-r','(-r)--remove'}"[Delete tag(s) from the current list]" )
|
187
187
|
;;
|
188
188
|
tags)
|
189
189
|
args=( "--bool[Boolean used to combine multiple tags]:BOOLEAN:" {'(--counts)-c','(-c)--counts'}"[Show count of occurrences]" "--case[Case sensitivity for search string matching ((c)ase-sensitive]:TYPE:" {'(--interactive)-i','(-i)--interactive'}"[Select items to scan from a menu of matching entries]" {'(--line)-l','(-l)--line'}"[Output in a single line with @ symbols]" "--not[Show items that *dont* match search/tag filterst* match search/tag filters]" {'(--order)-o','(-o)--order'}"[Sort order]:ORDER:" {'(--section)-s','(-s)--section'}"[Section]:SECTION_NAME:" "--search[Filter entries using a search query]:QUERY:" "--sort[Sort by name or count]:SORT_ORDER:" "--tag[Filter entries by tag]:TAG:" "--val[Perform a tag value query]:QUERY:" {'(--exact)-x','(-x)--exact'}"[Force exact search string matching]" )
|
data/lib/completion/doing.bash
CHANGED
@@ -321,9 +321,9 @@ _doing_tag() {
|
|
321
321
|
_doing_tag_dir() {
|
322
322
|
|
323
323
|
if [[ "$token" == --* ]]; then
|
324
|
-
COMPREPLY=( $( compgen -W '--remove' -- $token ) )
|
324
|
+
COMPREPLY=( $( compgen -W '--clear --editor --remove' -- $token ) )
|
325
325
|
elif [[ "$token" == -* ]]; then
|
326
|
-
COMPREPLY=( $( compgen -W '-r --remove' -- $token ) )
|
326
|
+
COMPREPLY=( $( compgen -W '-e -r --clear --editor --remove' -- $token ) )
|
327
327
|
|
328
328
|
fi
|
329
329
|
}
|
data/lib/completion/doing.fish
CHANGED
@@ -505,7 +505,9 @@ complete -c doing -l unfinished -s u -f -n '__fish_doing_using_command tag' -d
|
|
505
505
|
complete -c doing -l value -s v -f -r -n '__fish_doing_using_command tag' -d Include\ a\ value
|
506
506
|
complete -c doing -l val -f -r -n '__fish_doing_using_command tag' -d Perform\ a\ tag\ value\ query
|
507
507
|
complete -c doing -l exact -s x -f -n '__fish_doing_using_command tag' -d Force\ exact\ search\ string\ matching
|
508
|
-
complete -c doing -l
|
508
|
+
complete -c doing -l clear -f -n '__fish_doing_using_command tag_dir' -d Remove\ all\ default_tags\ from\ the\ local
|
509
|
+
complete -c doing -l editor -s e -f -n '__fish_doing_using_command tag_dir' -d Use\ default\ editor\ to\ edit\ tag\ list
|
510
|
+
complete -c doing -l remove -s r -f -n '__fish_doing_using_command tag_dir' -d Delete\ tag\(s\)\ from\ the\ current\ list
|
509
511
|
complete -c doing -l bool -f -r -n '__fish_doing_using_command tags' -d Boolean\ used\ to\ combine\ multiple\ tags
|
510
512
|
complete -c doing -l counts -s c -f -n '__fish_doing_using_command tags' -d Show\ count\ of\ occurrences
|
511
513
|
complete -c doing -l case -f -r -n '__fish_doing_using_command tags' -d Case\ sensitivity\ for\ search\ string\ matching\ \[\(c\)ase-sensitive
|
data/lib/doing/array/array.rb
CHANGED
@@ -3,18 +3,22 @@
|
|
3
3
|
require_relative 'tags'
|
4
4
|
require_relative 'nested_hash'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
6
|
+
module Doing
|
7
|
+
class ::Array
|
8
|
+
include ArrayTags
|
9
|
+
include ArrayNestedHash
|
10
|
+
##
|
11
|
+
## Force UTF-8 encoding of strings in array
|
12
|
+
##
|
13
|
+
## @return [Array] Encoded lines
|
14
|
+
##
|
15
|
+
def utf8
|
16
|
+
c = self.class
|
17
|
+
if String.method_defined? :force_encoding
|
18
|
+
replace c.new(map(&:utf8))
|
19
|
+
else
|
20
|
+
self
|
21
|
+
end
|
18
22
|
end
|
19
23
|
end
|
20
24
|
end
|
data/lib/doing/array/tags.rb
CHANGED
@@ -4,12 +4,14 @@ module Doing
|
|
4
4
|
##
|
5
5
|
## Array helpers
|
6
6
|
##
|
7
|
-
|
7
|
+
module ArrayTags
|
8
8
|
##
|
9
9
|
## Convert an array of @tags to plain strings
|
10
10
|
##
|
11
|
-
## @return [Array] array of strings
|
11
|
+
## @return [Array] array of strings without @ symbols
|
12
12
|
##
|
13
|
+
## @example Convert an array of tags to strings
|
14
|
+
## ['@one', '@two', 'three'].to_tags => ['one', 'two', 'three']
|
13
15
|
def tags_to_array
|
14
16
|
map(&:remove_at).map(&:strip)
|
15
17
|
end
|
@@ -18,9 +20,8 @@ module Doing
|
|
18
20
|
#
|
19
21
|
# @return [Array] Array of @tags
|
20
22
|
#
|
21
|
-
# @example
|
22
|
-
# ['one', '@two', 'three'].to_tags
|
23
|
-
# # => ['@one', '@two', '@three']
|
23
|
+
# @example Convert an array of strings with or without @ symbols
|
24
|
+
# ['one', '@two', 'three'].to_tags => ['@one', '@two', '@three']
|
24
25
|
def to_tags
|
25
26
|
map(&:add_at)
|
26
27
|
end
|
data/lib/doing/chronify/array.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Doing
|
4
4
|
# Chronify array helpers
|
5
|
-
|
5
|
+
module ChronifyArray
|
6
6
|
# Convert [d, h, m] to [y, d, h, m]
|
7
7
|
def to_years
|
8
8
|
d, h, m = self
|
@@ -56,8 +56,6 @@ module Doing
|
|
56
56
|
##
|
57
57
|
## Format [d, h, m] as string
|
58
58
|
##
|
59
|
-
## @accept [Array] Array of [days, hours, minutes]
|
60
|
-
##
|
61
59
|
## @param format [Symbol] The format, :dhm, :hm,
|
62
60
|
## :m, :clock, :natural
|
63
61
|
## @return [String] formatted string
|
@@ -3,3 +3,15 @@
|
|
3
3
|
require_relative 'array'
|
4
4
|
require_relative 'numeric'
|
5
5
|
require_relative 'string'
|
6
|
+
|
7
|
+
class ::String
|
8
|
+
include Doing::ChronifyString
|
9
|
+
end
|
10
|
+
|
11
|
+
class ::Array
|
12
|
+
include Doing::ChronifyArray
|
13
|
+
end
|
14
|
+
|
15
|
+
class ::Numeric
|
16
|
+
include Doing::ChronifyNumeric
|
17
|
+
end
|
@@ -4,11 +4,12 @@ module Doing
|
|
4
4
|
##
|
5
5
|
## Number helpers
|
6
6
|
##
|
7
|
-
|
7
|
+
module ChronifyNumeric
|
8
8
|
##
|
9
9
|
## Format human readable time from seconds
|
10
10
|
##
|
11
|
-
## @param
|
11
|
+
## @param human [Boolean] if True, don't convert
|
12
|
+
## hours into days
|
12
13
|
##
|
13
14
|
def format_time(human: false)
|
14
15
|
return [0, 0, 0] if nil?
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Doing
|
2
|
+
module Completion
|
3
|
+
module StringUtils
|
4
|
+
def short_desc
|
5
|
+
split(/[,.]/)[0].sub(/ \(.*?\)?$/, '').strip
|
6
|
+
end
|
7
|
+
|
8
|
+
def ltrunc(max)
|
9
|
+
if length > max
|
10
|
+
sub(/^.*?(.{#{max - 3}})$/, '...\1')
|
11
|
+
else
|
12
|
+
self
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def ltrunc!(max)
|
17
|
+
replace ltrunc(max)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class ::String
|
24
|
+
include Doing::Completion::StringUtils
|
25
|
+
end
|
data/lib/doing/completion.rb
CHANGED
data/lib/doing/good.rb
CHANGED
data/lib/doing/item/dates.rb
CHANGED
@@ -1,15 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
5
|
-
require_relative '
|
6
|
-
require_relative '
|
3
|
+
require_relative 'dates'
|
4
|
+
require_relative 'tags'
|
5
|
+
require_relative 'state'
|
6
|
+
require_relative 'query'
|
7
7
|
|
8
8
|
module Doing
|
9
9
|
##
|
10
10
|
## This class describes a single WWID item
|
11
11
|
##
|
12
12
|
class Item
|
13
|
+
include ItemDates
|
14
|
+
include ItemQuery
|
15
|
+
include ItemState
|
16
|
+
include ItemTags
|
17
|
+
|
13
18
|
attr_accessor :date, :title, :section, :note
|
14
19
|
|
15
20
|
# attr_reader :id
|
@@ -56,7 +61,7 @@ module Doing
|
|
56
61
|
|
57
62
|
return false unless @note.equal?(other.note)
|
58
63
|
|
59
|
-
return false if match_section &&
|
64
|
+
return false if match_section && !@section.equal?(other.section)
|
60
65
|
|
61
66
|
true
|
62
67
|
end
|
data/lib/doing/item/query.rb
CHANGED
data/lib/doing/item/state.rb
CHANGED
data/lib/doing/item/tags.rb
CHANGED
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doing
|
4
|
+
class Items < Array
|
5
|
+
# Get a new Items object containing only items in a
|
6
|
+
# specified section
|
7
|
+
#
|
8
|
+
# @param section [String] section title
|
9
|
+
#
|
10
|
+
# @return [Items] Array of items
|
11
|
+
#
|
12
|
+
def in_section(section)
|
13
|
+
if section =~ /^all$/i
|
14
|
+
dup
|
15
|
+
else
|
16
|
+
items = Items.new.concat(select { |item| !item.nil? && item.section == section })
|
17
|
+
items.add_section(section, log: false)
|
18
|
+
items
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
## Search Items for a string (title and note)
|
24
|
+
##
|
25
|
+
## @param query [String] The query
|
26
|
+
## @param case_type [Symbol] The case type
|
27
|
+
## (:smart, :sensitive, :ignore)
|
28
|
+
##
|
29
|
+
## @return [Items] array of items matching search
|
30
|
+
##
|
31
|
+
def search(query, case_type: :smart)
|
32
|
+
WWID.new.fuzzy_filter_items(self, query, case_type: case_type)
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
## Search items by tags
|
37
|
+
##
|
38
|
+
## @param tags [Array,String] The tags by which to
|
39
|
+
## filter
|
40
|
+
## @param bool [Symbol] The bool with which to
|
41
|
+
## combine multiple tags
|
42
|
+
##
|
43
|
+
## @return [Items] array of items matching tag filter
|
44
|
+
##
|
45
|
+
def tagged(tags, bool: :and)
|
46
|
+
WWID.new.filter_items(self, opt: { tag: tags, bool: bool })
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
## Filter Items by date. String arguments will be
|
51
|
+
## chronified
|
52
|
+
##
|
53
|
+
## @param start [Time,String] Filter items after
|
54
|
+
## this date
|
55
|
+
## @param finish [Time,String] Filter items before
|
56
|
+
## this date
|
57
|
+
##
|
58
|
+
## @return [Items] array of items with dates between
|
59
|
+
## targets
|
60
|
+
##
|
61
|
+
def between_dates(start, finish)
|
62
|
+
start = start.chronify(guess: :begin, future: false) if start.is_a?(String)
|
63
|
+
finish = finish.chronify(guess: :end) if finish.is_a?(String)
|
64
|
+
WWID.new.filter_items(self, opt: { date_filter: [start, finish] })
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'filter'
|
4
|
+
require_relative 'modify'
|
5
|
+
require_relative 'sections'
|
6
|
+
require_relative 'util'
|
7
|
+
|
8
|
+
module Doing
|
9
|
+
# A collection of Item objects
|
10
|
+
class Items < Array
|
11
|
+
attr_accessor :sections
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
super
|
15
|
+
@sections = []
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
## Test if self includes Item
|
20
|
+
##
|
21
|
+
## @param item [Item] The item to search for
|
22
|
+
## @param match_section [Boolean] Section must match
|
23
|
+
##
|
24
|
+
## @return [Boolean] True if Item exists
|
25
|
+
##
|
26
|
+
def include?(item, match_section: true)
|
27
|
+
includes = false
|
28
|
+
each do |other_item|
|
29
|
+
if other_item.equal?(item, match_section: match_section)
|
30
|
+
includes = true
|
31
|
+
break
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
includes
|
36
|
+
end
|
37
|
+
|
38
|
+
# Output sections and items in Doing file format
|
39
|
+
def to_s
|
40
|
+
out = []
|
41
|
+
@sections.each do |section|
|
42
|
+
out.push(section.original)
|
43
|
+
items = in_section(section.title).sort_by { |i| [i.date, i.title] }
|
44
|
+
items.reverse! if Doing.setting('doing_file_sort').normalize_order == :desc
|
45
|
+
items.each { |item| out.push(item.to_s) }
|
46
|
+
end
|
47
|
+
|
48
|
+
out.join("\n")
|
49
|
+
end
|
50
|
+
|
51
|
+
# @private
|
52
|
+
def inspect
|
53
|
+
sections = @sections.map { |s| "<Section:#{s.title} #{in_section(s.title).count} items>" }.join(', ')
|
54
|
+
"#<Doing::Items #{count} items, #{@sections.count} sections: #{sections}>"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doing
|
4
|
+
class Items < Array
|
5
|
+
##
|
6
|
+
## Delete an item from the index
|
7
|
+
##
|
8
|
+
## @param item The item
|
9
|
+
##
|
10
|
+
def delete_item(item, single: false)
|
11
|
+
deleted = delete(item)
|
12
|
+
Doing.logger.count(:deleted)
|
13
|
+
Doing.logger.info('Entry deleted:', deleted.title) if single
|
14
|
+
deleted
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
## Update an item in the index with a modified item
|
19
|
+
##
|
20
|
+
## @param old_item The old item
|
21
|
+
## @param new_item The new item
|
22
|
+
##
|
23
|
+
def update_item(old_item, new_item)
|
24
|
+
s_idx = index { |item| item.equal?(old_item) }
|
25
|
+
|
26
|
+
raise ItemNotFound, 'Unable to find item in index, did it mutate?' unless s_idx
|
27
|
+
|
28
|
+
return if fetch(s_idx).equal?(new_item)
|
29
|
+
|
30
|
+
self[s_idx] = new_item
|
31
|
+
Doing.logger.count(:updated)
|
32
|
+
Doing.logger.info('Entry updated:', self[s_idx].title.trunc(60))
|
33
|
+
new_item
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doing
|
4
|
+
class Items < Array
|
5
|
+
# List sections, title only
|
6
|
+
#
|
7
|
+
# @return [Array] section titles
|
8
|
+
#
|
9
|
+
def section_titles
|
10
|
+
@sections.map(&:title)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Test if section already exists
|
14
|
+
#
|
15
|
+
# @param section [String] section title
|
16
|
+
#
|
17
|
+
# @return [Boolean] true if section exists
|
18
|
+
#
|
19
|
+
def section?(section)
|
20
|
+
section = section.is_a?(Section) ? section.title.downcase : section.downcase
|
21
|
+
@sections.map { |i| i.title.downcase }.include?(section)
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
## Return the best section match for a search query
|
26
|
+
##
|
27
|
+
## @param frag The search query
|
28
|
+
## @param distance The distance apart characters can be (fuzziness)
|
29
|
+
##
|
30
|
+
## @return [Section] (first) matching section object
|
31
|
+
##
|
32
|
+
def guess_section(frag, distance: 2)
|
33
|
+
section = nil
|
34
|
+
re = frag.to_rx(distance: distance, case_type: :ignore)
|
35
|
+
@sections.each do |sect|
|
36
|
+
next unless sect.title =~ /#{re}/i
|
37
|
+
|
38
|
+
Doing.logger.debug('Match:', %(Assuming "#{sect.title}" from "#{frag}"))
|
39
|
+
section = sect
|
40
|
+
break
|
41
|
+
end
|
42
|
+
|
43
|
+
section
|
44
|
+
end
|
45
|
+
|
46
|
+
# Add a new section to the sections array. Accepts
|
47
|
+
# either a Section object, or a title string that will
|
48
|
+
# be converted into a Section.
|
49
|
+
#
|
50
|
+
# @param section [Section] The section to add. A
|
51
|
+
# String value will be converted to
|
52
|
+
# Section automatically.
|
53
|
+
# @param log [Boolean] Add a log message
|
54
|
+
# notifying the user about the
|
55
|
+
# creation of the section.
|
56
|
+
#
|
57
|
+
# @return nothing
|
58
|
+
#
|
59
|
+
def add_section(section, log: false)
|
60
|
+
section = section.is_a?(Section) ? section : Section.new(section.cap_first)
|
61
|
+
|
62
|
+
return if section?(section)
|
63
|
+
|
64
|
+
@sections.push(section)
|
65
|
+
Doing.logger.info('New section:', %("#{section}" added)) if log
|
66
|
+
end
|
67
|
+
|
68
|
+
def delete_section(section, log: false)
|
69
|
+
return unless section?(section)
|
70
|
+
|
71
|
+
raise DoingRuntimeError, 'Section not empty' if in_section(section).count.positive?
|
72
|
+
|
73
|
+
@sections.each do |sect|
|
74
|
+
next unless sect.title == section && in_section(sect).count.zero?
|
75
|
+
|
76
|
+
@sections.delete(sect)
|
77
|
+
Doing.logger.info('Removed section:', %("#{section}" removed)) if log
|
78
|
+
end
|
79
|
+
|
80
|
+
Doing.logger.error('Not found:', %("#{section}" not found))
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|