Commit 7f4beb62cf
Verified · cmc
Layout: unified · split
Sources/OrgCore/Agenda/AgendaFilter.swift +13 −4
| @@ -13,10 +13,19 @@ public struct AgendaFilter: Sendable, Equatable { | ||
| 13 | 13 | |
| 14 | 14 | public var isEmpty: Bool { categories.isEmpty && tags.isEmpty && efforts.isEmpty && regexps.isEmpty } |
| 15 | 15 | |
| 16 | /// The filter as `/` shows it for editing. | |
| 16 | /// The filter as `/` shows it for editing; `parse` reads it back to the same filter. | |
| 17 | /// Categories holding `-` are quoted. | |
| 17 | 18 | public var description: String { |
| 18 | let regexp = regexps.first.map { "/" + $0.dropFirst().replacingOccurrences(of: "^\\+", with: "", options: .regularExpression) + "/" } ?? "" | |
| 19 | return categories.joined() + tags.joined() + (efforts.first.map { String($0.dropFirst()) } ?? "") + regexp | |
| 19 | func unsigned(_ term: String) -> (sign: String, body: String) { | |
| 20 | (term.hasPrefix("-") ? "-" : "", String(term.dropFirst())) | |
| 21 | } | |
| 22 | let cats = categories.map { term -> String in | |
| 23 | let (sign, body) = unsigned(term) | |
| 24 | return (sign.isEmpty ? "+" : sign) + (body.contains("-") ? "\"\(body)\"" : body) | |
| 25 | } | |
| 26 | let efforts = efforts.map { unsigned($0).sign + unsigned($0).body } | |
| 27 | let regexps = regexps.map { unsigned($0).sign + "/" + unsigned($0).body + "/" } | |
| 28 | return (cats + tags + efforts + regexps).joined() | |
| 20 | 29 | } |
| 21 | 30 | |
| 22 | 31 | /// Reads `+cat-tag<0:10-/regexp/`: a word is a tag if a shown line has it, else a category |
| @@ -43,7 +52,7 @@ public struct AgendaFilter: Sendable, Equatable { | ||
| 43 | 52 | let word = ns.substring(with: m.range(at: 3)).replacingOccurrences(of: "~~~", with: "-") |
| 44 | 53 | if shownTags.contains(word) { |
| 45 | 54 | append(sign + word, to: &result.tags) |
| 46 | } else if shownCategories.contains(word) { | |
| 55 | } else if shownCategories.contains(word.replacingOccurrences(of: "^\"(.*)\"$", with: "$1", options: .regularExpression)) { | |
| 47 | 56 | append(sign + word.replacingOccurrences(of: "^\"(.*)\"$", with: "$1", options: .regularExpression), to: &result.categories) |
| 48 | 57 | } else { |
| 49 | 58 | ignored.append(sign + word) |
Tests/OrgCoreTests/AgendaTests.swift +10
| @@ -536,4 +536,14 @@ struct AgendaFilterTests { | ||
| 536 | 536 | let kept = filter.parse("++urgent", tags: ["urgent"], categories: []).filter |
| 537 | 537 | #expect(kept.tags == ["-phone", "+urgent"]) |
| 538 | 538 | } |
| 539 | ||
| 540 | @Test func descriptionRoundTrips() { | |
| 541 | let tags: Set<String> = ["phone", "urgent"], categories: Set<String> = ["work", "my-cat"] | |
| 542 | for text in ["-/call/", "-work+phone-<0:10>1:00/a/-/b/", "\"my-cat\"-urgent", "-\"my-cat\""] { | |
| 543 | let filter = AgendaFilter().parse(text, tags: tags, categories: categories).filter | |
| 544 | #expect(AgendaFilter().parse(filter.description, tags: tags, categories: categories).filter == filter, "\(text)") | |
| 545 | } | |
| 546 | let negative = AgendaFilter().parse("-/call/", tags: [], categories: []).filter | |
| 547 | #expect(negative.description == "-/call/") | |
| 548 | } | |
| 539 | 549 | } |