icalPal 3.1.1 → 3.3.0
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/README.md +19 -19
- data/bin/icalPal +111 -56
- data/bin/icalpal +111 -56
- data/icalPal.gemspec +37 -9
- data/lib/EventKit.rb +24 -18
- data/lib/ToICalPal.rb +28 -26
- data/lib/calendar.rb +1 -2
- data/lib/defaults.rb +8 -7
- data/lib/event.rb +56 -55
- data/lib/icalPal.rb +26 -46
- data/lib/options.rb +40 -36
- data/lib/rdt.rb +7 -5
- data/lib/reminder.rb +22 -22
- data/lib/store.rb +1 -1
- data/lib/utils.rb +45 -0
- data/lib/version.rb +2 -2
- metadata +18 -13
data/bin/icalpal
CHANGED
@@ -11,6 +11,7 @@ begin
|
|
11
11
|
|
12
12
|
require_relative '../lib/icalpal'
|
13
13
|
require_relative '../lib/options'
|
14
|
+
require_relative '../lib/utils'
|
14
15
|
rescue LoadError => e
|
15
16
|
dep = e.message[/-- (.*)/, 1]
|
16
17
|
|
@@ -27,10 +28,15 @@ end
|
|
27
28
|
|
28
29
|
# All kids love log!
|
29
30
|
$log = Logger.new(STDERR, { level: $defaults[:common][:debug] })
|
30
|
-
$log.formatter = proc do |s, t,
|
31
|
+
$log.formatter = proc do |s, t, _p, m| # Severity, time, progname, msg
|
31
32
|
($log.level.positive?)? "#{s}: #{m}\n" :
|
32
|
-
"[%-
|
33
|
-
|
33
|
+
format("[%-5<sev>s] %<time>s [%<caller>s] - %<message>s\n",
|
34
|
+
{
|
35
|
+
sev: s,
|
36
|
+
time: t.strftime('%H:%M:%S.%L'),
|
37
|
+
caller: caller(4, 1)[0].split('/')[-1],
|
38
|
+
message: m
|
39
|
+
})
|
34
40
|
end
|
35
41
|
|
36
42
|
$opts = ICalPal::Options.new.parse_options
|
@@ -53,7 +59,7 @@ $log.info("Options: #{$opts}")
|
|
53
59
|
def add(item)
|
54
60
|
$log.info("Adding #{item.inspect} #{item['UUID']} (#{item['title']})") if item['UUID']
|
55
61
|
|
56
|
-
item['sday'] = ICalPal::RDT.new(*item['sdate'].to_a[0..2]) if
|
62
|
+
item['sday'] = ICalPal::RDT.new(*item['sdate'].to_a[0..2]) if ICalPal::Event === item && item['sdate']
|
57
63
|
$items.push(item)
|
58
64
|
end
|
59
65
|
|
@@ -62,22 +68,63 @@ end
|
|
62
68
|
# Load the data
|
63
69
|
|
64
70
|
# What are we getting?
|
65
|
-
klass = ICalPal
|
71
|
+
klass = ICalPal.call($opts[:cmd])
|
72
|
+
success = false
|
66
73
|
|
67
74
|
# Get it
|
68
75
|
$opts[:db].each do |db|
|
69
|
-
|
76
|
+
$log.debug("Trying #{db}")
|
70
77
|
|
71
|
-
|
78
|
+
if klass == ICalPal::Reminder
|
79
|
+
begin
|
72
80
|
# Load all .sqlite files
|
73
81
|
$log.debug("Loading *.sqlite in #{db}")
|
74
|
-
Dir.glob("#{db}/*.sqlite").each
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
82
|
+
Dir.glob("#{db}/*.sqlite").each do |d|
|
83
|
+
$rows += ICalPal.load_data(d, klass::QUERY)
|
84
|
+
success = true
|
85
|
+
|
86
|
+
rescue SQLite3::CantOpenException
|
87
|
+
# Non-fatal exception, try the next one
|
79
88
|
end
|
89
|
+
end
|
90
|
+
else
|
91
|
+
# Load database
|
92
|
+
begin
|
93
|
+
$rows += ICalPal.load_data(db, klass::QUERY)
|
94
|
+
success = true
|
95
|
+
|
96
|
+
rescue SQLite3::CantOpenException
|
97
|
+
# Non-fatal exception, try the next one
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Make sure we opened at least one database
|
103
|
+
unless success
|
104
|
+
$log.fatal('Could not open database')
|
105
|
+
|
106
|
+
# SQLite3 does not return useful error messages. If any databases
|
107
|
+
# failed because of EPERM (operation not permitted), our parent
|
108
|
+
# process might need Full Disk Access, and we should suggest that.
|
109
|
+
eperm = 0
|
110
|
+
|
111
|
+
$opts[:db].each do |db|
|
112
|
+
# Use a real open to get a useful error
|
113
|
+
File.open(db).close
|
114
|
+
rescue Exception => e
|
115
|
+
$log.fatal("#{e.class}: #{db}")
|
116
|
+
|
117
|
+
eperm = 1 if e.instance_of?(Errno::EPERM)
|
80
118
|
end
|
119
|
+
|
120
|
+
if eperm.positive?
|
121
|
+
$stderr.puts
|
122
|
+
$stderr.puts "Does #{ancestor} have Full Disk Access in System Settings?"
|
123
|
+
$stderr.puts
|
124
|
+
$stderr.puts "Try running: open 'x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles'"
|
125
|
+
end
|
126
|
+
|
127
|
+
abort
|
81
128
|
end
|
82
129
|
|
83
130
|
$log.info("Loaded #{$rows.count} #{klass} rows")
|
@@ -91,25 +138,25 @@ $rows.each_with_index do |row, i|
|
|
91
138
|
$log.debug("Row #{i}: #{row['ROWID']}:#{row['UUID']} - #{row['account']}/#{row['calendar']}/#{row['title']}")
|
92
139
|
|
93
140
|
# --es/--is
|
94
|
-
if $opts[:es].any? row['account']
|
95
|
-
$log.debug(
|
141
|
+
if $opts[:es].any? row['account']
|
142
|
+
$log.debug(':es')
|
96
143
|
next
|
97
144
|
end
|
98
145
|
|
99
|
-
unless $opts[:is].empty?
|
100
|
-
$log.debug(
|
146
|
+
unless $opts[:is].empty? || ($opts[:is].any? row['account'])
|
147
|
+
$log.debug(':is')
|
101
148
|
next
|
102
149
|
end
|
103
150
|
|
104
151
|
# --ec/--ic
|
105
|
-
unless klass == ICalPal::Store
|
106
|
-
if $opts[:ec].any? row['calendar']
|
107
|
-
$log.debug(
|
152
|
+
unless klass == ICalPal::Store || !row['calendar']
|
153
|
+
if $opts[:ec].any? row['calendar']
|
154
|
+
$log.debug(':ec')
|
108
155
|
next
|
109
156
|
end
|
110
157
|
|
111
|
-
unless $opts[:ic].empty?
|
112
|
-
$log.debug(
|
158
|
+
unless $opts[:ic].empty? || ($opts[:ic].any? row['calendar'])
|
159
|
+
$log.debug(':ic')
|
113
160
|
next
|
114
161
|
end
|
115
162
|
end
|
@@ -118,24 +165,24 @@ $rows.each_with_index do |row, i|
|
|
118
165
|
item = klass.new(row)
|
119
166
|
|
120
167
|
# --et/--it
|
121
|
-
if $opts[:et].any? item['type']
|
122
|
-
$log.debug(
|
168
|
+
if $opts[:et].any? item['type']
|
169
|
+
$log.debug(':et')
|
123
170
|
next
|
124
171
|
end
|
125
172
|
|
126
|
-
unless $opts[:it].empty?
|
127
|
-
$log.debug(
|
173
|
+
unless $opts[:it].empty? || ($opts[:it].any? item['type'])
|
174
|
+
$log.debug(':it')
|
128
175
|
next
|
129
176
|
end
|
130
177
|
|
131
178
|
# --el/--il
|
132
|
-
if $opts[:el].any? item['list_name']
|
133
|
-
$log.debug(
|
179
|
+
if $opts[:el].any? item['list_name']
|
180
|
+
$log.debug(':el')
|
134
181
|
next
|
135
182
|
end
|
136
183
|
|
137
|
-
unless $opts[:il].empty?
|
138
|
-
$log.debug(
|
184
|
+
unless $opts[:il].empty? || ($opts[:il].any? item['list_name'])
|
185
|
+
$log.debug(':il')
|
139
186
|
next
|
140
187
|
end
|
141
188
|
|
@@ -144,8 +191,8 @@ $rows.each_with_index do |row, i|
|
|
144
191
|
r = $opts[:match].split('=')
|
145
192
|
|
146
193
|
if item[r[0]].to_s.respond_to?(:match)
|
147
|
-
unless item[r[0]].to_s.match(Regexp.new(r[1].to_s, Regexp::IGNORECASE))
|
148
|
-
$log.debug(
|
194
|
+
unless item[r[0]].to_s.match(Regexp.new(r[1].to_s, Regexp::IGNORECASE))
|
195
|
+
$log.debug(':match')
|
149
196
|
next
|
150
197
|
end
|
151
198
|
end
|
@@ -153,18 +200,18 @@ $rows.each_with_index do |row, i|
|
|
153
200
|
|
154
201
|
if ICalPal::Event === item
|
155
202
|
# Check for all-day and cancelled events
|
156
|
-
if $opts[:ea] && item['all_day'].positive?
|
157
|
-
$log.debug(
|
203
|
+
if $opts[:ea] && item['all_day'].positive?
|
204
|
+
$log.debug(':ea')
|
158
205
|
next
|
159
206
|
end
|
160
207
|
|
161
|
-
if $opts[:ia] && !item['all_day'].positive?
|
162
|
-
$log.debug(
|
208
|
+
if $opts[:ia] && !item['all_day'].positive?
|
209
|
+
$log.debug(':ia')
|
163
210
|
next
|
164
211
|
end
|
165
212
|
|
166
|
-
if item['status'] == :canceled
|
167
|
-
$log.debug(
|
213
|
+
if item['status'] == :canceled
|
214
|
+
$log.debug(':canceled')
|
168
215
|
next
|
169
216
|
end
|
170
217
|
|
@@ -173,14 +220,14 @@ $rows.each_with_index do |row, i|
|
|
173
220
|
item.non_recurring.each { |i| add(i) }
|
174
221
|
else
|
175
222
|
# Check for dated reminders
|
176
|
-
if ICalPal::Reminder === item
|
177
|
-
if $opts[:dated] == 1
|
178
|
-
$log.debug(
|
223
|
+
if ICalPal::Reminder === item
|
224
|
+
if $opts[:dated] == 1 && item['due_date'].positive?
|
225
|
+
$log.debug(':undated')
|
179
226
|
next
|
180
227
|
end
|
181
228
|
|
182
|
-
if $opts[:dated] == 2
|
183
|
-
$log.debug(
|
229
|
+
if $opts[:dated] == 2 && item['due_date'].zero?
|
230
|
+
$log.debug(':dated')
|
184
231
|
next
|
185
232
|
end
|
186
233
|
end
|
@@ -216,7 +263,7 @@ $log.debug("#{$items.count} items remain")
|
|
216
263
|
mu = case $opts[:output]
|
217
264
|
when 'ansi' then RDoc::Markup::ToAnsi.new
|
218
265
|
when 'default' then RDoc::Markup::ToICalPal.new($opts)
|
219
|
-
when 'html'
|
266
|
+
when 'html'
|
220
267
|
rdoc = RDoc::Options.new
|
221
268
|
rdoc.pipe = true
|
222
269
|
rdoc.output_decoration = false
|
@@ -236,7 +283,7 @@ unless mu
|
|
236
283
|
$log.debug("Output in #{$opts[:output]} format")
|
237
284
|
|
238
285
|
puts case $opts[:output]
|
239
|
-
when 'csv'
|
286
|
+
when 'csv'
|
240
287
|
# Get all headers
|
241
288
|
headers = []
|
242
289
|
items.each { |i| headers += i.keys }
|
@@ -249,15 +296,15 @@ unless mu
|
|
249
296
|
table
|
250
297
|
when 'hash' then items.map { |i| i.self }
|
251
298
|
when 'json' then items.map { |i| i.self }.to_json
|
252
|
-
when 'xml'
|
253
|
-
xml = items.map { |i| "<#{$opts[:cmd].chomp(
|
254
|
-
"<#{$opts[:cmd]}>\n#{xml.join(
|
299
|
+
when 'xml'
|
300
|
+
xml = items.map { |i| "<#{$opts[:cmd].chomp('s')}>#{i.to_xml}</#{$opts[:cmd].chomp('s')}>" }
|
301
|
+
"<#{$opts[:cmd]}>\n#{xml.join('')}</#{$opts[:cmd]}>"
|
255
302
|
when 'yaml' then items.map { |i| i.self }.to_yaml
|
256
303
|
when 'remind' then items.map { |i|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
304
|
+
"REM #{i['sdate'].strftime('%F AT %R')} " +
|
305
|
+
"DURATION #{((i['edate'] - i['sdate']).to_f * 1440).to_i} " +
|
306
|
+
"MSG #{i['title']}"
|
307
|
+
}.join("\n")
|
261
308
|
else abort "No formatter for #{$opts[:output]}"
|
262
309
|
end
|
263
310
|
|
@@ -302,20 +349,28 @@ items.each_with_index do |i, j|
|
|
302
349
|
|
303
350
|
next unless value
|
304
351
|
next if Array === value && !value[0]
|
305
|
-
next if String === value && value.
|
352
|
+
next if String === value && value.empty?
|
306
353
|
|
307
354
|
$log.debug("#{prop}: #{value}")
|
308
355
|
|
309
356
|
# Use Raw to save the property
|
310
357
|
props << RDoc::Markup::Raw.new(prop)
|
311
358
|
|
312
|
-
|
359
|
+
if k.positive?
|
360
|
+
props << RDoc::Markup::BlankLine.new unless (i['placeholder'] || $opts[:ps])
|
361
|
+
props << RDoc::Markup::ListItem.new(prop, RDoc::Markup::Paragraph.new(value)) unless (i['placeholder'])
|
362
|
+
else
|
313
363
|
# First property, value only
|
314
364
|
props << RDoc::Markup::Heading.new(2, value.to_s)
|
315
|
-
else
|
316
|
-
props << RDoc::Markup::BlankLine.new unless (i['placeholder'] || $opts[:ps])
|
317
|
-
props << RDoc::Markup::ListItem.new(prop, RDoc::Markup::Paragraph.new(value)) unless(i['placeholder'])
|
318
365
|
end
|
366
|
+
|
367
|
+
# unless k.positive?
|
368
|
+
# # First property, value only
|
369
|
+
# props << RDoc::Markup::Heading.new(2, value.to_s)
|
370
|
+
# else
|
371
|
+
# props << RDoc::Markup::BlankLine.new unless (i['placeholder'] || $opts[:ps])
|
372
|
+
# props << RDoc::Markup::ListItem.new(prop, RDoc::Markup::Paragraph.new(value)) unless (i['placeholder'])
|
373
|
+
# end
|
319
374
|
end
|
320
375
|
|
321
376
|
# Print it
|
data/icalPal.gemspec
CHANGED
@@ -1,27 +1,55 @@
|
|
1
|
-
|
1
|
+
require_relative 'lib/version'
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = ICalPal::NAME
|
5
5
|
s.version = ICalPal::VERSION
|
6
6
|
|
7
|
-
s.summary =
|
7
|
+
s.summary = 'Command-line tool to query the macOS Calendar'
|
8
8
|
s.description = <<-EOF
|
9
9
|
Inspired by icalBuddy and maintains close compatability. Includes
|
10
10
|
many additional features for querying, filtering, and formatting.
|
11
11
|
EOF
|
12
12
|
|
13
|
-
s.authors =
|
14
|
-
s.email =
|
13
|
+
s.authors = 'Andy Rosen'
|
14
|
+
s.email = 'ajr@corp.mlfs.org'
|
15
15
|
s.homepage = "https://github.com/ajrosen/#{s.name}"
|
16
|
-
s.licenses = [
|
16
|
+
s.licenses = [ 'GPL-3.0-or-later' ]
|
17
17
|
|
18
|
-
s.
|
18
|
+
s.metadata = {
|
19
|
+
'bug_tracker_uri' => "https://github.com/ajrosen/#{s.name}/issues"
|
20
|
+
}
|
21
|
+
|
22
|
+
s.files = Dir["#{s.name}.gemspec", 'bin/*', 'lib/*.rb']
|
19
23
|
s.executables = [ "#{s.name}" ]
|
20
|
-
s.extra_rdoc_files = [
|
24
|
+
s.extra_rdoc_files = [ 'README.md' ]
|
25
|
+
|
26
|
+
s.add_dependency 'nokogiri-plist', '~> 0.5.0'
|
27
|
+
s.add_dependency 'sqlite3', '~> 2.6.0' unless s.rubygems_version == `/usr/bin/gem --version`.strip
|
21
28
|
|
22
|
-
|
23
|
-
|
29
|
+
# The macOS and Homebrew versions of rubygems have incompatible
|
30
|
+
# requirements for sqlite3.
|
31
|
+
#
|
32
|
+
# macOS comes with version 1.3.13, so it does not need to be added
|
33
|
+
# as a dependency, but it cannot install anything newer:
|
34
|
+
#
|
35
|
+
# requires Ruby version >= 3.0, < 3.4.dev. The current ruby version is 2.6.10.
|
36
|
+
#
|
37
|
+
# Homebrew's Ruby formula does not come with sqlite3, so it does
|
38
|
+
# need to be added as a dependency, but it cannot install version
|
39
|
+
# 1.3.13:
|
40
|
+
#
|
41
|
+
# error: call to undeclared function
|
42
|
+
#
|
43
|
+
# So we must call add_dependency, but iff we are not building with
|
44
|
+
# macOS' Ruby installation.
|
24
45
|
|
25
46
|
s.bindir = 'bin'
|
26
47
|
s.required_ruby_version = '>= 2.6.0'
|
48
|
+
|
49
|
+
s.post_install_message = <<-EOF
|
50
|
+
|
51
|
+
Note: #{ICalPal::NAME} requires "Full Disk Access" in System Settings to access your calendar.
|
52
|
+
Make sure the program that runs #{ICalPal::NAME}, not #{ICalPal::NAME} itself, has these permissions.
|
53
|
+
|
54
|
+
EOF
|
27
55
|
end
|
data/lib/EventKit.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
+
# rubocop: disable Naming/ConstantName
|
2
|
+
|
1
3
|
# Constants from EventKit[https://developer.apple.com/documentation/eventkit/]
|
4
|
+
|
2
5
|
class EventKit
|
3
|
-
EKEntityType = [
|
4
|
-
|
5
|
-
|
6
|
-
]
|
6
|
+
EKEntityType = %w[
|
7
|
+
event
|
8
|
+
reminder
|
9
|
+
].freeze
|
7
10
|
|
8
11
|
EKEventAvailability = {
|
9
12
|
notSupported: -1,
|
@@ -11,28 +14,28 @@ class EventKit
|
|
11
14
|
free: 1,
|
12
15
|
tentative: 2,
|
13
16
|
unavailable: 3,
|
14
|
-
}
|
17
|
+
}.freeze
|
15
18
|
|
16
19
|
EKEventStatus = {
|
17
20
|
none: 0,
|
18
21
|
confirmed: 1,
|
19
22
|
tentative: 2,
|
20
23
|
canceled: 3,
|
21
|
-
}
|
24
|
+
}.freeze
|
22
25
|
|
23
|
-
EKRecurrenceFrequency = [
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
]
|
26
|
+
EKRecurrenceFrequency = %w[
|
27
|
+
daily
|
28
|
+
weekly
|
29
|
+
monthly
|
30
|
+
yearly
|
31
|
+
].freeze
|
29
32
|
|
30
33
|
EKReminderProperty = [
|
31
34
|
'none', # 0
|
32
35
|
'high', nil, nil, nil, # 1
|
33
36
|
'medium', nil, nil, nil, # 5
|
34
37
|
'low', # 9
|
35
|
-
]
|
38
|
+
].freeze
|
36
39
|
|
37
40
|
# EKSourceType (with color)
|
38
41
|
EKSourceType = [
|
@@ -43,10 +46,13 @@ class EventKit
|
|
43
46
|
{ name: 'Subscribed', color: '#FF0000' }, # Red
|
44
47
|
{ name: 'Birthdays', color: '#FF00FF' }, # Magenta
|
45
48
|
{ name: 'Reminders', color: '#066FF3' }, # Blue
|
46
|
-
]
|
49
|
+
].freeze
|
50
|
+
|
51
|
+
EKSpan = %w[
|
52
|
+
this
|
53
|
+
future
|
54
|
+
].freeze
|
47
55
|
|
48
|
-
EKSpan = [
|
49
|
-
'this',
|
50
|
-
'future',
|
51
|
-
]
|
52
56
|
end
|
57
|
+
|
58
|
+
# rubocop: enable Naming/ConstantName
|
data/lib/ToICalPal.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
##################################################
|
2
2
|
# Render an RDoc::Markup::Document, closely mimicking
|
3
3
|
# icalBuddy[https://github.com/ali-rantakari/icalBuddy]
|
4
|
-
|
5
4
|
class RDoc::Markup::ToICalPal < RDoc::Markup::Formatter
|
6
5
|
# Standard
|
7
6
|
# ANSI[https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-T.416-199303-I!!PDF-E&type=items]
|
@@ -26,25 +25,25 @@ class RDoc::Markup::ToICalPal < RDoc::Markup::Formatter
|
|
26
25
|
'pink': '38;2;255;45;85',
|
27
26
|
'purple': '38;2;204;115;225',
|
28
27
|
'rose': '38;2;217;166;159',
|
29
|
-
}
|
28
|
+
}.freeze
|
30
29
|
|
31
30
|
# Increased intensity
|
32
|
-
BOLD = '%c[1m'
|
31
|
+
BOLD = format('%c[1m', 27.chr)
|
33
32
|
|
34
33
|
# Default rendition
|
35
|
-
NORM = '%c[0m'
|
34
|
+
NORM = format('%c[0m', 27.chr)
|
36
35
|
|
37
36
|
# Properties for which we don't include labels
|
38
|
-
NO_LABEL = [
|
37
|
+
NO_LABEL = %w[ title datetime ].freeze
|
39
38
|
|
40
39
|
# Properties that are always colorized
|
41
|
-
COLOR_LABEL = [
|
40
|
+
COLOR_LABEL = %w[ title calendar ].freeze
|
42
41
|
|
43
42
|
# Default color for labels
|
44
|
-
LABEL_COLOR = [ 'cyan', '#00ffff' ]
|
43
|
+
LABEL_COLOR = [ 'cyan', '#00ffff' ].freeze
|
45
44
|
|
46
45
|
# Color for datetime value
|
47
|
-
DATE_COLOR = [ 'yellow', '#ffff00' ]
|
46
|
+
DATE_COLOR = [ 'yellow', '#ffff00' ].freeze
|
48
47
|
|
49
48
|
# @param opts [Hash] Used for conditional formatting
|
50
49
|
# @option opts [String] :bullet Bullet
|
@@ -56,6 +55,7 @@ class RDoc::Markup::ToICalPal < RDoc::Markup::Formatter
|
|
56
55
|
# @option opts [Array<String>] :ps List of property separators
|
57
56
|
# @option opts [String] :ss Section separator
|
58
57
|
def initialize(opts)
|
58
|
+
super(opts)
|
59
59
|
@opts = opts
|
60
60
|
end
|
61
61
|
|
@@ -72,15 +72,15 @@ class RDoc::Markup::ToICalPal < RDoc::Markup::Formatter
|
|
72
72
|
|
73
73
|
# Add a bullet for the first property of an item
|
74
74
|
#
|
75
|
-
# @param
|
76
|
-
def accept_list_start(
|
75
|
+
# @param _arg [Array] Ignored
|
76
|
+
def accept_list_start(_arg)
|
77
77
|
begin
|
78
78
|
return if @item['placeholder']
|
79
79
|
rescue
|
80
80
|
end
|
81
81
|
|
82
82
|
begin
|
83
|
-
if (@item['due_date'] + ICalPal::ITIME).between?(ICalPal::ITIME + 1, $now.to_i)
|
83
|
+
if (@item['due_date'] + ICalPal::ITIME).between?(ICalPal::ITIME + 1, $now.to_i)
|
84
84
|
@res << "#{@opts[:ab]} " unless @opts[:nb]
|
85
85
|
return
|
86
86
|
end
|
@@ -96,15 +96,15 @@ class RDoc::Markup::ToICalPal < RDoc::Markup::Formatter
|
|
96
96
|
# @option arg [String] .label Contains the property name
|
97
97
|
def accept_list_item_start(arg)
|
98
98
|
@res << @opts[:ps][@ps] || ' ' unless @item['placeholder']
|
99
|
-
@res << colorize(*LABEL_COLOR, arg.label) <<
|
99
|
+
@res << colorize(*LABEL_COLOR, arg.label) << ': ' unless @opts[:npn] || NO_LABEL.any?(arg.label)
|
100
100
|
|
101
101
|
@ps += 1 unless @ps == @opts[:ps].count - 1
|
102
102
|
end
|
103
103
|
|
104
104
|
# Add a blank line
|
105
105
|
#
|
106
|
-
# @param
|
107
|
-
def accept_blank_line(*
|
106
|
+
# @param *_arg [Array] Ignored
|
107
|
+
def accept_blank_line(*_arg)
|
108
108
|
@res << "\n"
|
109
109
|
end
|
110
110
|
|
@@ -119,9 +119,9 @@ class RDoc::Markup::ToICalPal < RDoc::Markup::Formatter
|
|
119
119
|
@res << h.text
|
120
120
|
|
121
121
|
case h.level
|
122
|
-
when 1
|
123
|
-
@res <<
|
124
|
-
when 2
|
122
|
+
when 1
|
123
|
+
@res << ':'
|
124
|
+
when 2
|
125
125
|
if @prop == 'title' && @item['calendar']
|
126
126
|
@res << bold(" (#{@item['calendar']})") unless @opts[:nc] || @item['title'] == @item['calendar']
|
127
127
|
end
|
@@ -140,8 +140,8 @@ class RDoc::Markup::ToICalPal < RDoc::Markup::Formatter
|
|
140
140
|
|
141
141
|
# Add a section separator
|
142
142
|
#
|
143
|
-
# @param
|
144
|
-
def accept_rule(
|
143
|
+
# @param _weight Ignored
|
144
|
+
def accept_rule(_weight)
|
145
145
|
@res << @opts[:ss]
|
146
146
|
accept_blank_line
|
147
147
|
end
|
@@ -167,6 +167,7 @@ class RDoc::Markup::ToICalPal < RDoc::Markup::Formatter
|
|
167
167
|
# @return [String] str with increased intensity[#BOLD]
|
168
168
|
def bold(str)
|
169
169
|
return str unless @opts[:palette]
|
170
|
+
|
170
171
|
BOLD + str + NORM
|
171
172
|
end
|
172
173
|
|
@@ -177,27 +178,28 @@ class RDoc::Markup::ToICalPal < RDoc::Markup::Formatter
|
|
177
178
|
return str unless c8 && c24 && @opts[:palette]
|
178
179
|
|
179
180
|
case @opts[:palette]
|
180
|
-
when 8
|
181
|
+
when 8 # Default colour table
|
181
182
|
c = ANSI[c8.downcase.to_sym]
|
182
183
|
c ||= ANSI[c24[0..6].downcase.to_sym]
|
183
184
|
c ||= ANSI[:white]
|
184
185
|
|
185
|
-
when 24
|
186
|
+
when 24 # Direct colour in RGB space
|
186
187
|
rgb = c24[1..].split(/(\h\h)(\h\h)(\h\h)/)
|
187
188
|
rgb.map! { |i| i.to_i(16) }
|
188
189
|
c = [ 38, 2, rgb[1..] ].join(';')
|
189
190
|
end
|
190
191
|
|
191
|
-
|
192
|
+
# esc c str esc ansi
|
193
|
+
format('%<esc>c[%<color>sm%<string>s%<esc>c[%<ansi_default>sm',
|
194
|
+
{ esc: 27.chr, color: c, string: str, ansi_default: ANSI[:default] })
|
192
195
|
end
|
193
196
|
|
194
197
|
# @!visibility private
|
195
198
|
|
196
199
|
# @param a [Array] Ignored
|
197
|
-
def accept_list_end(a)
|
198
|
-
end
|
200
|
+
def accept_list_end(a) end
|
199
201
|
|
200
202
|
# @param a [Array] Ignored
|
201
|
-
def accept_list_item_end(a)
|
202
|
-
|
203
|
+
def accept_list_item_end(a) end
|
204
|
+
|
203
205
|
end
|
data/lib/calendar.rb
CHANGED
@@ -3,7 +3,7 @@ module ICalPal
|
|
3
3
|
class Calendar
|
4
4
|
include ICalPal
|
5
5
|
|
6
|
-
QUERY = <<~SQL
|
6
|
+
QUERY = <<~SQL.freeze
|
7
7
|
SELECT DISTINCT
|
8
8
|
|
9
9
|
Store.name AS account,
|
@@ -16,7 +16,6 @@ JOIN Store ON store_id = Store.rowid
|
|
16
16
|
|
17
17
|
WHERE Store.disabled IS NOT 1
|
18
18
|
AND Store.display_order IS NOT -1
|
19
|
-
AND (Calendar.display_order IS NOT -1 OR external_rep IS NOT NULL)
|
20
19
|
AND Calendar.flags IS NOT 519
|
21
20
|
SQL
|
22
21
|
|
data/lib/defaults.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Does anybody really know what time it is?
|
2
2
|
$now = ICalPal::RDT.now
|
3
|
-
$today = ICalPal::RDT.new(*$now.to_a[0..2] + [0, 0, 0, $now.zone])
|
3
|
+
$today = ICalPal::RDT.new(*$now.to_a[0..2] + [ 0, 0, 0, $now.zone ])
|
4
4
|
|
5
5
|
# Defaults
|
6
6
|
$defaults = {
|
@@ -40,27 +40,27 @@ $defaults = {
|
|
40
40
|
tasks: {
|
41
41
|
dated: 0,
|
42
42
|
db: [ ICalPal::Reminder::DB_PATH ],
|
43
|
-
iep: [
|
43
|
+
iep: %w[ title notes due priority ],
|
44
44
|
sort: 'prio',
|
45
45
|
},
|
46
46
|
undatedTasks: {
|
47
47
|
dated: 1,
|
48
48
|
db: [ ICalPal::Reminder::DB_PATH ],
|
49
|
-
iep: [
|
49
|
+
iep: %w[ title notes due priority ],
|
50
50
|
sort: 'prio',
|
51
51
|
},
|
52
52
|
datedTasks: {
|
53
53
|
dated: 2,
|
54
54
|
db: [ ICalPal::Reminder::DB_PATH ],
|
55
|
-
iep: [
|
55
|
+
iep: %w[ title notes due priority ],
|
56
56
|
sort: 'prio',
|
57
57
|
},
|
58
58
|
stores: {
|
59
|
-
iep: [
|
59
|
+
iep: %w[ account type ],
|
60
60
|
sort: 'account',
|
61
61
|
},
|
62
62
|
calendars: {
|
63
|
-
iep: [
|
63
|
+
iep: %w[ calendar type UUID ],
|
64
64
|
sort: 'calendar',
|
65
65
|
},
|
66
66
|
events: {
|
@@ -69,10 +69,11 @@ $defaults = {
|
|
69
69
|
eed: false,
|
70
70
|
eep: [],
|
71
71
|
from: $today,
|
72
|
-
iep: [
|
72
|
+
iep: %w[ title location notes url attendees datetime ],
|
73
73
|
n: false,
|
74
74
|
nnr: "\n ",
|
75
75
|
nrd: false,
|
76
|
+
now: false,
|
76
77
|
ps: [ "\n " ],
|
77
78
|
sa: false,
|
78
79
|
sed: false,
|