Skip to content

Commit 2957e38

Browse files
authored
Add sorting reminders when showing (#57)
1 parent 06955a3 commit 2957e38

File tree

3 files changed

+57
-7
lines changed

3 files changed

+57
-7
lines changed

Sources/RemindersLibrary/CLI.swift

+12-1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,16 @@ private struct Show: ParsableCommand {
5050
@Flag(help: "Include completed items in output")
5151
var includeCompleted = false
5252

53+
@Option(
54+
name: .shortAndLong,
55+
help: "Show the reminders in a specific order, one of: \(Sort.commaSeparatedCases)")
56+
var sort: Sort = .none
57+
58+
@Option(
59+
name: [.customShort("o"), .long],
60+
help: "How the sort order should be applied, one of: \(CustomSortOrder.commaSeparatedCases)")
61+
var sortOrder: CustomSortOrder = .ascending
62+
5363
@Option(
5464
name: .shortAndLong,
5565
help: "Show only reminders due on this date")
@@ -76,7 +86,8 @@ private struct Show: ParsableCommand {
7686
}
7787

7888
reminders.showListItems(
79-
withName: self.listName, dueOn: self.dueDate, displayOptions: displayOptions, outputFormat: format)
89+
withName: self.listName, dueOn: self.dueDate, displayOptions: displayOptions,
90+
outputFormat: format, sort: sort, sortOrder: sortOrder)
8091
}
8192
}
8293

Sources/RemindersLibrary/Reminders.swift

+11-6
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@ private extension EKReminder {
1616
}
1717
}
1818

19-
private func format(_ reminder: EKReminder, at index: Int, listName: String? = nil) -> String {
19+
private func format(_ reminder: EKReminder, at index: Int?, listName: String? = nil) -> String {
2020
let dateString = formattedDueDate(from: reminder).map { " (\($0))" } ?? ""
2121
let priorityString = Priority(reminder.mappedPriority).map { " (priority: \($0))" } ?? ""
2222
let listString = listName.map { "\($0): " } ?? ""
2323
let notesString = reminder.notes.map { " (\($0))" } ?? ""
24-
return "\(listString)\(index): \(reminder.title ?? "<unknown>")\(notesString)\(dateString)\(priorityString)"
24+
let indexString = index.map { "\($0): " } ?? ""
25+
return "\(listString)\(indexString)\(reminder.title ?? "<unknown>")\(notesString)\(dateString)\(priorityString)"
2526
}
2627

2728
public enum OutputFormat: String, ExpressibleByArgument {
@@ -128,15 +129,19 @@ public final class Reminders {
128129
semaphore.wait()
129130
}
130131

131-
func showListItems(withName name: String, dueOn dueDate: DateComponents?, displayOptions: DisplayOptions, outputFormat: OutputFormat) {
132+
func showListItems(withName name: String, dueOn dueDate: DateComponents?, displayOptions: DisplayOptions,
133+
outputFormat: OutputFormat, sort: Sort, sortOrder: CustomSortOrder)
134+
{
132135
let semaphore = DispatchSemaphore(value: 0)
133136
let calendar = Calendar.current
134137

135138
self.reminders(on: [self.calendar(withName: name)], displayOptions: displayOptions) { reminders in
136-
var matchingReminders = [(EKReminder, Int)]()
139+
var matchingReminders = [(EKReminder, Int?)]()
140+
let reminders = sort == .none ? reminders : reminders.sorted(by: sort.sortFunction(order: sortOrder))
137141
for (i, reminder) in reminders.enumerated() {
142+
let index = sort == .none ? i : nil
138143
guard let dueDate = dueDate?.date else {
139-
matchingReminders.append((reminder, i))
144+
matchingReminders.append((reminder, index))
140145
continue
141146
}
142147

@@ -147,7 +152,7 @@ public final class Reminders {
147152
let sameDay = calendar.compare(
148153
reminderDueDate, to: dueDate, toGranularity: .day) == .orderedSame
149154
if sameDay {
150-
matchingReminders.append((reminder, i))
155+
matchingReminders.append((reminder, index))
151156
}
152157
}
153158

Sources/RemindersLibrary/Sort.swift

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import ArgumentParser
2+
import EventKit
3+
4+
public enum Sort: String, Decodable, ExpressibleByArgument, CaseIterable {
5+
case none
6+
case creationDate = "creation-date"
7+
case dueDate = "due-date"
8+
9+
public static let commaSeparatedCases = Self.allCases.map { $0.rawValue }.joined(separator: ", ")
10+
11+
func sortFunction(order: CustomSortOrder) -> (EKReminder, EKReminder) -> Bool {
12+
let comparison: (Date, Date) -> Bool = order == .ascending ? (<) : (>)
13+
switch self {
14+
case .none: return { _, _ in fatalError() }
15+
case .creationDate: return { comparison($0.creationDate!, $1.creationDate!) }
16+
case .dueDate: return {
17+
switch ($0.dueDateComponents, $1.dueDateComponents) {
18+
case (.none, .none): return false
19+
case (.none, .some): return false
20+
case (.some, .none): return true
21+
case (.some, .some): return comparison($0.dueDateComponents!.date!, $1.dueDateComponents!.date!)
22+
}
23+
}
24+
}
25+
}
26+
}
27+
28+
// TODO: Replace with SortOrder when we drop < macOS 12.0
29+
public enum CustomSortOrder: String, Decodable, ExpressibleByArgument, CaseIterable {
30+
case ascending
31+
case descending
32+
33+
public static let commaSeparatedCases = Self.allCases.map { $0.rawValue }.joined(separator: ", ")
34+
}

0 commit comments

Comments
 (0)