doing 2.1.45 → 2.1.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/.irbrc +3 -0
  3. data/CHANGELOG.md +13 -0
  4. data/Gemfile.lock +1 -1
  5. data/README.md +1 -1
  6. data/bin/commands/reset.rb +6 -4
  7. data/docs/doc/Array.html +1 -1
  8. data/docs/doc/BooleanTermParser/Clause.html +1 -1
  9. data/docs/doc/BooleanTermParser/Operator.html +1 -1
  10. data/docs/doc/BooleanTermParser/Query.html +1 -1
  11. data/docs/doc/BooleanTermParser/QueryParser.html +1 -1
  12. data/docs/doc/BooleanTermParser/QueryTransformer.html +1 -1
  13. data/docs/doc/BooleanTermParser.html +1 -1
  14. data/docs/doc/Doing/ArrayCleanup.html +1 -1
  15. data/docs/doc/Doing/ArrayNestedHash.html +1 -1
  16. data/docs/doc/Doing/ArrayTags.html +1 -1
  17. data/docs/doc/Doing/CSVExport.html +1 -1
  18. data/docs/doc/Doing/CalendarImport.html +1 -1
  19. data/docs/doc/Doing/Change.html +1 -1
  20. data/docs/doc/Doing/Changes.html +1 -1
  21. data/docs/doc/Doing/ChronifyArray.html +1 -1
  22. data/docs/doc/Doing/ChronifyNumeric.html +1 -1
  23. data/docs/doc/Doing/ChronifyString.html +1 -1
  24. data/docs/doc/Doing/Color.html +1 -1
  25. data/docs/doc/Doing/Completion/BashCompletions.html +1 -1
  26. data/docs/doc/Doing/Completion/FishCompletions.html +1 -1
  27. data/docs/doc/Doing/Completion/StringUtils.html +1 -1
  28. data/docs/doc/Doing/Completion/ZshCompletions.html +1 -1
  29. data/docs/doc/Doing/Completion.html +1 -1
  30. data/docs/doc/Doing/Configuration.html +1 -1
  31. data/docs/doc/Doing/DayOneRenderer.html +1 -1
  32. data/docs/doc/Doing/DayoneExport.html +1 -1
  33. data/docs/doc/Doing/DoingImport.html +1 -1
  34. data/docs/doc/Doing/Entry.html +1 -1
  35. data/docs/doc/Doing/Errors/DoingNoTraceError.html +1 -1
  36. data/docs/doc/Doing/Errors/DoingRuntimeError.html +1 -1
  37. data/docs/doc/Doing/Errors/DoingStandardError.html +1 -1
  38. data/docs/doc/Doing/Errors/EmptyInput.html +1 -1
  39. data/docs/doc/Doing/Errors/HistoryLimitError.html +1 -1
  40. data/docs/doc/Doing/Errors/InvalidPlugin.html +1 -1
  41. data/docs/doc/Doing/Errors/MissingBackupFile.html +1 -1
  42. data/docs/doc/Doing/Errors/NoResults.html +1 -1
  43. data/docs/doc/Doing/Errors/PluginException.html +1 -1
  44. data/docs/doc/Doing/Errors/UserCancelled.html +1 -1
  45. data/docs/doc/Doing/Errors/WrongCommand.html +1 -1
  46. data/docs/doc/Doing/Errors.html +1 -1
  47. data/docs/doc/Doing/HTMLExport.html +1 -1
  48. data/docs/doc/Doing/Hooks.html +1 -1
  49. data/docs/doc/Doing/Item.html +75 -36
  50. data/docs/doc/Doing/ItemDates.html +1 -1
  51. data/docs/doc/Doing/ItemQuery.html +1 -1
  52. data/docs/doc/Doing/ItemState.html +1 -1
  53. data/docs/doc/Doing/ItemTags.html +1 -1
  54. data/docs/doc/Doing/Items.html +129 -1
  55. data/docs/doc/Doing/JSONExport.html +1 -1
  56. data/docs/doc/Doing/Logger.html +1 -1
  57. data/docs/doc/Doing/MarkdownExport.html +1 -1
  58. data/docs/doc/Doing/Note.html +1 -1
  59. data/docs/doc/Doing/Pager.html +1 -1
  60. data/docs/doc/Doing/Plugins.html +1 -1
  61. data/docs/doc/Doing/Prompt.html +1 -1
  62. data/docs/doc/Doing/PromptChoose.html +1 -1
  63. data/docs/doc/Doing/PromptFZF.html +1 -1
  64. data/docs/doc/Doing/PromptInput.html +1 -1
  65. data/docs/doc/Doing/PromptSTD.html +1 -1
  66. data/docs/doc/Doing/PromptYN.html +1 -1
  67. data/docs/doc/Doing/Section.html +1 -1
  68. data/docs/doc/Doing/StringHighlight.html +1 -1
  69. data/docs/doc/Doing/StringNormalize.html +1 -1
  70. data/docs/doc/Doing/StringQuery.html +1 -1
  71. data/docs/doc/Doing/StringTags.html +1 -1
  72. data/docs/doc/Doing/StringTransform.html +1 -1
  73. data/docs/doc/Doing/StringTruncate.html +1 -1
  74. data/docs/doc/Doing/StringURL.html +1 -1
  75. data/docs/doc/Doing/SymbolNormalize.html +1 -1
  76. data/docs/doc/Doing/TaskPaperExport.html +1 -1
  77. data/docs/doc/Doing/TemplateExport.html +1 -1
  78. data/docs/doc/Doing/TemplateString.html +2 -2
  79. data/docs/doc/Doing/TimingImport.html +1 -1
  80. data/docs/doc/Doing/Types.html +1 -1
  81. data/docs/doc/Doing/Util/Backup.html +1 -1
  82. data/docs/doc/Doing/Util.html +2 -2
  83. data/docs/doc/Doing/Version.html +1 -1
  84. data/docs/doc/Doing/WWID.html +1 -1
  85. data/docs/doc/Doing.html +4 -4
  86. data/docs/doc/FalseClass.html +1 -1
  87. data/docs/doc/GLI/Commands/Help.html +1 -1
  88. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
  89. data/docs/doc/GLI/Commands.html +1 -1
  90. data/docs/doc/GLI.html +1 -1
  91. data/docs/doc/Hash.html +1 -1
  92. data/docs/doc/Numeric.html +1 -1
  93. data/docs/doc/Object.html +1 -1
  94. data/docs/doc/PhraseParser/Operator.html +1 -1
  95. data/docs/doc/PhraseParser/PhraseClause.html +1 -1
  96. data/docs/doc/PhraseParser/Query.html +1 -1
  97. data/docs/doc/PhraseParser/QueryParser.html +1 -1
  98. data/docs/doc/PhraseParser/QueryTransformer.html +1 -1
  99. data/docs/doc/PhraseParser/TermClause.html +1 -1
  100. data/docs/doc/PhraseParser.html +1 -1
  101. data/docs/doc/Status.html +1 -1
  102. data/docs/doc/String.html +63 -1
  103. data/docs/doc/Symbol.html +1 -1
  104. data/docs/doc/Time.html +1 -1
  105. data/docs/doc/TrueClass.html +1 -1
  106. data/docs/doc/_index.html +8 -1
  107. data/docs/doc/class_list.html +1 -1
  108. data/docs/doc/file.README.html +2 -2
  109. data/docs/doc/index.html +2 -2
  110. data/docs/doc/method_list.html +409 -361
  111. data/docs/doc/top-level-namespace.html +1 -1
  112. data/doing.rdoc +3 -3
  113. data/lib/doing/item/item.rb +7 -8
  114. data/lib/doing/items/items.rb +24 -0
  115. data/lib/doing/plugins/export/json_export.rb +16 -2
  116. data/lib/doing/plugins/import/json_import.rb +93 -0
  117. data/lib/doing/string/string.rb +9 -0
  118. data/lib/doing/version.rb +1 -1
  119. data/lib/doing/wwid/filetools.rb +3 -2
  120. data/lib/doing/wwid/filter.rb +2 -2
  121. data/lib/doing.rb +1 -0
  122. metadata +3 -2
@@ -216,7 +216,7 @@
216
216
  </div>
217
217
 
218
218
  <div id="footer">
219
- Generated on Tue Mar 22 10:06:15 2022 by
219
+ Generated on Wed Mar 23 08:25:50 2022 by
220
220
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
221
221
  0.9.27 (ruby-3.0.1).
222
222
  </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.45
8
+ v2.1.46
9
9
 
10
10
  === Global Options
11
11
  === --config_file arg
@@ -1055,7 +1055,7 @@ List commands one per line, to assist with shell completion
1055
1055
  ==== Command: <tt>import PATH</tt>
1056
1056
  Import entries from an external source
1057
1057
 
1058
- Imports entries from other sources. Available plugins: calendar, capturething, doing, timing
1058
+ Imports entries from other sources. Available plugins: calendar, capturething, doing, json, timing
1059
1059
  ===== Options
1060
1060
  ===== --after DATE_STRING
1061
1061
 
@@ -1123,7 +1123,7 @@ Tag all imported entries
1123
1123
 
1124
1124
  ===== --type TYPE
1125
1125
 
1126
- Import type (calendar|capturething|doing|timing)
1126
+ Import type (calendar|capturething|doing|json|timing)
1127
1127
 
1128
1128
  [Default Value] doing
1129
1129
 
@@ -15,7 +15,7 @@ module Doing
15
15
  include ItemState
16
16
  include ItemTags
17
17
 
18
- attr_accessor :date, :title, :section, :note
18
+ attr_accessor :date, :title, :section, :note, :id
19
19
 
20
20
  # attr_reader :id
21
21
 
@@ -31,19 +31,18 @@ module Doing
31
31
  ## the item belongs
32
32
  ## @param note [Array or String] The note
33
33
  ## (optional)
34
+ ## @param id MD5 identifier
34
35
  ##
35
- def initialize(date, title, section, note = nil)
36
+ def initialize(date, title, section, note = nil, id = nil)
36
37
  @date = date.is_a?(Time) ? date : Time.parse(date)
37
38
  @title = title
38
39
  @section = section
39
40
  @note = Note.new(note)
41
+ @id = id&.valid_id? ? id.strip : gen_id
40
42
  end
41
43
 
42
- # Generate a hash that represents the entry
43
- #
44
- # @return [String] entry hash
45
- def id
46
- @id ||= (@date.to_s + @title + @section).hash
44
+ def gen_id
45
+ Digest::MD5.hexdigest(to_s)
47
46
  end
48
47
 
49
48
  ##
@@ -91,7 +90,7 @@ module Doing
91
90
 
92
91
  # outputs item in Doing file format, including leading tab
93
92
  def to_s
94
- "\t- #{@date.strftime('%Y-%m-%d %H:%M')} | #{@title}#{@note.good? ? "\n#{@note}" : ''}"
93
+ "\t- #{@date.strftime('%Y-%m-%d %H:%M')} | #{@title} <#{@id}>#{@note.good? ? "\n#{@note}" : ''}"
95
94
  end
96
95
 
97
96
  ##
@@ -35,6 +35,30 @@ module Doing
35
35
  includes
36
36
  end
37
37
 
38
+ # Find an item by ID
39
+ #
40
+ # @param id The identifier to match
41
+ #
42
+ def find_id(id)
43
+ select { |item| item.id == id }[0]
44
+ end
45
+
46
+ ##
47
+ ## Return the index for an entry matching ID
48
+ ##
49
+ ## @param id The identifier to match
50
+ ##
51
+ def index_for_id(id)
52
+ i = nil
53
+ each_with_index do |item, idx|
54
+ if item.id == id
55
+ i = idx
56
+ break
57
+ end
58
+ end
59
+ i
60
+ end
61
+
38
62
  # Output sections and items in Doing file format
39
63
  def to_s
40
64
  out = []
@@ -15,7 +15,18 @@ module Doing
15
15
  end
16
16
 
17
17
  def self.render(wwid, items, variables: {})
18
- return if items.nil?
18
+ if items.nil? || items.empty?
19
+ return case variables[:options][:output]
20
+ when 'json'
21
+ {
22
+ 'section' => '',
23
+ 'items' => [],
24
+ 'timers' => ""
25
+ }.to_json
26
+ when 'timeline'
27
+ "<html></html>"
28
+ end
29
+ end
19
30
 
20
31
  opt = variables[:options]
21
32
  opt[:output] = case opt[:output]
@@ -25,6 +36,7 @@ module Doing
25
36
  'json'
26
37
  end
27
38
  items_out = []
39
+
28
40
  last_date = items[-1].date + (60 * 60 * 24)
29
41
  max = last_date.strftime('%F')
30
42
  min = items[0].date.strftime('%F')
@@ -51,10 +63,12 @@ module Doing
51
63
  date: i.date,
52
64
  end_date: end_date,
53
65
  title: title.strip, #+ " #{note}"
66
+ section: i.section,
54
67
  note: note.to_s(prefix: ''),
55
68
  time: interval.time_string(format: :clock),
56
69
  duration: duration.time_string(format: :clock),
57
- tags: tags
70
+ tags: tags,
71
+ id: i.id
58
72
  }
59
73
 
60
74
  attributes.each { |attr, val| i[attr.to_sym] = val }
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ # title: JSON Import
4
+ # description: Import entries from a Doing JSON export
5
+ # author: Brett Terpstra
6
+ # url: https://brettterpstra.com
7
+ module Doing
8
+ class JSONImport
9
+ include Doing::Util
10
+
11
+ def self.settings
12
+ {
13
+ trigger: 'json'
14
+ }
15
+ end
16
+
17
+ ##
18
+ ## Imports a Timing report
19
+ ##
20
+ ## @param wwid [WWID] The wwid object
21
+ ## @param path [String] Path to JSON report
22
+ ## file
23
+ ## @param options [Hash] Additional Options
24
+ ##
25
+ def self.import(wwid, path, options: {})
26
+ exit_now! 'Path to JSON export required' if path.nil?
27
+ options[:no_overlap] ||= false
28
+ options[:autotag] ||= Doing.auto_tag
29
+
30
+ exit_now! 'File not found' unless File.exist?(File.expand_path(path))
31
+
32
+ updated = 0
33
+ added = 0
34
+ skipped = 0
35
+
36
+ data = JSON.parse(IO.read(File.expand_path(path)))
37
+ new_items = []
38
+ new_section = options[:section] || Doing.setting('current_section')
39
+
40
+ data['items'].each do |entry|
41
+ title = entry['title']
42
+ date = Time.parse(entry['date'])
43
+ date ||= entry['date'].chronify
44
+ note = Doing::Note.new(entry['note'])
45
+ section = if entry['section'].empty?
46
+ new_section
47
+ else
48
+ entry['section']
49
+ end
50
+ id = entry.key?('id') ? entry['id'] : nil
51
+
52
+ new_item = Doing::Item.new(date, title, section, note, id)
53
+
54
+ is_match = true
55
+
56
+ if options[:search]
57
+ is_match = new_item.search(options[:search], case_type: options[:case], negate: options[:not])
58
+ end
59
+
60
+ if is_match && options[:date_filter]
61
+ is_match = start_time > options[:date_filter][0] && start_time < options[:date_filter][1]
62
+ is_match = options[:not] ? !is_match : is_match
63
+ end
64
+
65
+ unless is_match
66
+ skipped += 1
67
+ next
68
+
69
+ end
70
+
71
+ if wwid.content.find_id(new_item.id)
72
+ old_index = wwid.content.index_for_id(entry['id'])
73
+ old_item = wwid.content[old_index].clone
74
+ wwid.content[old_index] = new_item
75
+ Hooks.trigger :post_entry_updated, self, new_item, old_item
76
+ updated += 1
77
+ else
78
+ Hooks.trigger :pre_entry_add, self, item
79
+ wwid.content << new_entry
80
+ Hooks.trigger :post_entry_added, self, item
81
+ added += 1
82
+ end
83
+ end
84
+ total = new_items.count
85
+ skipped = data.count - total
86
+ Doing.logger.debug('Skipped:', %(#{skipped} items)) if skipped.positive?
87
+ Doing.logger.info('Updated:', %(#{updated} items))
88
+ Doing.logger.info('Imported:', %(#{added} new items to #{new_section}))
89
+ end
90
+
91
+ Doing::Plugins.register 'json', :import, self
92
+ end
93
+ end
@@ -16,6 +16,15 @@ class ::String
16
16
  include Doing::StringTruncate
17
17
  include Doing::StringURL
18
18
 
19
+ ##
20
+ ## Test if string is a valid 32-character MD5 id
21
+ ##
22
+ ## @return [Boolean] string is valid identifier
23
+ ##
24
+ def valid_id?
25
+ strip =~ /^[a-z0-9]{32}$/ ? true : false
26
+ end
27
+
19
28
  ##
20
29
  ## Force UTF-8 encoding if available
21
30
  ##
data/lib/doing/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Doing
2
- VERSION = '2.1.45'
2
+ VERSION = '2.1.46'
3
3
  end
@@ -40,7 +40,7 @@ module Doing
40
40
  if line =~ /^(\S[\S ]+):\s*(@[\w\-_.]+\s*)*$/
41
41
  section = Regexp.last_match(1)
42
42
  @content.add_section(Section.new(section, original: line), log: false)
43
- elsif line =~ /^\s*- (\d{4}-\d\d-\d\d \d\d:\d\d) \| (.*)/
43
+ elsif line =~ /^\s*- (\d{4}-\d\d-\d\d \d\d:\d\d) \| (.*?)(?: +<([a-z0-9]{32})>)? *$/
44
44
  if section.nil?
45
45
  section = 'Uncategorized'
46
46
  @content.add_section(Section.new(section, original: 'Uncategorized:'), log: false)
@@ -48,7 +48,8 @@ module Doing
48
48
 
49
49
  date = Regexp.last_match(1).strip
50
50
  title = Regexp.last_match(2).strip
51
- item = Item.new(date, title, section)
51
+ id = Regexp.last_match(3) || nil
52
+ item = Item.new(date, title, section, [], id)
52
53
  @content.push(item)
53
54
  elsif @content.count.zero?
54
55
  # if content[section].items.length - 1 == current
@@ -146,8 +146,8 @@ module Doing
146
146
  end
147
147
 
148
148
  if keep && opt[:time_filter][0] || opt[:time_filter][1]
149
- opt[:time_filter][0] = '00:00' if opt[:time_filter][0] =~ /12 *am/i
150
- opt[:time_filter][1] = '00:00' if opt[:time_filter][1] =~ /12 *am/i
149
+ opt[:time_filter].map! { |v| v =~ /(12 *am|midnight)/i ? '00:00' : v }
150
+
151
151
  start_string = if opt[:time_filter][0].nil?
152
152
  "#{item.date.strftime('%Y-%m-%d')} 00:00"
153
153
  else
data/lib/doing.rb CHANGED
@@ -16,6 +16,7 @@ require 'json'
16
16
  require 'logger'
17
17
  require 'safe_yaml/load'
18
18
  require 'fcntl'
19
+ require 'digest'
19
20
 
20
21
  require 'chronic'
21
22
  require 'tty-link'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: doing
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.45
4
+ version: 2.1.46
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-22 00:00:00.000000000 Z
11
+ date: 2022-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: github-markup
@@ -677,6 +677,7 @@ files:
677
677
  - lib/doing/plugins/import/cal_to_json.scpt
678
678
  - lib/doing/plugins/import/calendar_import.rb
679
679
  - lib/doing/plugins/import/doing_import.rb
680
+ - lib/doing/plugins/import/json_import.rb
680
681
  - lib/doing/plugins/import/timing_import.rb
681
682
  - lib/doing/prompt/choose.rb
682
683
  - lib/doing/prompt/fzf.rb