krz/orgstar

A native macOS editor for org-mode files. editor org-mode swift

Commit 1d6a2cda53

1d6a2cda5366195c467051dc38b26571d54f4b9a

parent: eba8a09f88

Verified · cmc

cmc <hello@cleberg.net> · 2026-10-09 06:50 UTC

Match Emacs word syntax for \<, \>, \b, \B, \w and \W in agenda and sparse-tree regexps

Layout: unified · split

Sources/OrgCore/Agenda/AgendaSearch.swift +9 −3
@@ -480,6 +480,9 @@ public struct TagsMatcher: Sendable {
480480/// Emacs regular expressions run through ICU, case-insensitively as the matcher binds
481481/// `case-fold-search`.
482482enum EmacsRegex {
483 /// Word syntax in an Org buffer: letters, digits, marks, `$` and `%`, but not `_`, `-` or `'`.
484 static let word = "[\\p{L}\\p{N}\\p{M}$%\\u00b7]"
485
483486 static func translate(_ pattern: String) -> String {
484487 var out = ""
485488 var chars = Array(pattern)
@@ -522,11 +525,14 @@ enum EmacsRegex {
522525 out += n == "s" ? "[\\t\\n\\f\\r \\u00a0]" : "[^\\t\\n\\f\\r \\u00a0]"
523526 i += 3
524527 continue
525 case "<", ">": out += "\\b"
528 case "<": out += "(?<!\(word))(?=\(word))"
529 case ">": out += "(?<=\(word))(?!\(word))"
530 case "b": out += "(?:(?<!\(word))(?=\(word))|(?<=\(word))(?!\(word)))"
531 case "B": out += "(?:(?<=\(word))(?=\(word))|(?<!\(word))(?!\(word)))"
526532 case "`": out += "^"
527533 case "'": out += "$"
528 case "w": out += "[\\p{L}\\p{N}]"
529 case "W": out += "[^\\p{L}\\p{N}]"
534 case "w": out += word
535 case "W": out += "[^" + word.dropFirst()
530536 default: out += "\\" + String(n)
531537 }
532538 i += 2
Tests/OrgCoreTests/AgendaSearchTests.swift +4
@@ -28,6 +28,7 @@ struct AgendaSearchTests {
2828 * Two words
2929 The phrase two words
3030 spans here; foo_bar and foo-bar.
31 Costs $5 or 50% (don't) for the café.
3132 * The last
3233 word ends this entry with last
3334 * word starts the next heading
@@ -54,6 +55,9 @@ struct AgendaSearchTests {
5455 "+alpha", "+alpha -beta", "+alpha +gamma", "-alpha", "+beta -nested", "{alph?a}", "+{^Gam}", "-{b[eo]}",
5556 "+{\\<rent\\>}", "+\"two words\"", "+\"two words\"", "+\"the line\"", "{boiler\\b}", "+alpha +\"in the body\"",
5657 "+{foo\\s-bar}", "+boiler -plate", "+{a b}", "+{alpha} -{x y}",
58 // Emacs word syntax in Org buffers: `_`, `-` and `'` are not word characters; `$` and `%` are.
59 "+{\\<bar\\>}", "+{foo\\b}", "+{o\\B_}", "+{\\<5\\>}", "+{\\b50\\b}", "+{don\\>}", "+{\\w+_\\w+}", "+{\\W5}",
60 "+{caf\\w\\>}", "+{\\<\\$5}",
5761 // Headlines only.
5862 "*rent", "*alpha", "*+alpha -beta", "*+section", "*-alpha", "*pay rent", "*with alpha and",
5963 // TODO only and whole words.