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 | public var isEmpty: Bool { categories.isEmpty && tags.isEmpty && efforts.isEmpty && regexps.isEmpty } | 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 | public var description: String { | 18 | public var description: String { |
| 18 | let regexp = regexps.first.map { "/" + $0.dropFirst().replacingOccurrences(of: "^\\+", with: "", options: .regularExpression) + "/" } ?? "" | 19 | func unsigned(_ term: String) -> (sign: String, body: String) { |
| 19 | return categories.joined() + tags.joined() + (efforts.first.map { String($0.dropFirst()) } ?? "") + regexp | 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 | /// Reads `+cat-tag<0:10-/regexp/`: a word is a tag if a shown line has it, else a category | 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 | let word = ns.substring(with: m.range(at: 3)).replacingOccurrences(of: "~~~", with: "-") | 52 | let word = ns.substring(with: m.range(at: 3)).replacingOccurrences(of: "~~~", with: "-") |
| 44 | if shownTags.contains(word) { | 53 | if shownTags.contains(word) { |
| 45 | append(sign + word, to: &result.tags) | 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 | append(sign + word.replacingOccurrences(of: "^\"(.*)\"$", with: "$1", options: .regularExpression), to: &result.categories) | 56 | append(sign + word.replacingOccurrences(of: "^\"(.*)\"$", with: "$1", options: .regularExpression), to: &result.categories) |
| 48 | } else { | 57 | } else { |
| 49 | ignored.append(sign + word) | 58 | ignored.append(sign + word) |
Tests/OrgCoreTests/AgendaTests.swift +10
| @@ -536,4 +536,14 @@ struct AgendaFilterTests { | |||
| 536 | let kept = filter.parse("++urgent", tags: ["urgent"], categories: []).filter | 536 | let kept = filter.parse("++urgent", tags: ["urgent"], categories: []).filter |
| 537 | #expect(kept.tags == ["-phone", "+urgent"]) | 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 | } |